【问题标题】:Typescript + Angular2: Subscribing to Observable causes "Unrecognized teardown 1" errorTypescript + Angular2:订阅 Observable 导致“无法识别的拆解 1”错误
【发布时间】:2016-08-07 22:09:35
【问题描述】:

我在 Angular2.rc.4 Typescript 应用程序中使用 Observable 时遇到问题。我在这里有一个plunker: https://embed.plnkr.co/UjcdCmN6hSkdKt27ezyI/

本质上,该应用程序有一个具有以下代码的服务:

private messageSender : Observable<string>;

constructor() {
    this.messageSender = Observable.create(observer => this.clients.push(observer));
 }

public listenForMessages() : any {
    console.log("Listen Requested...")
    return this.messageSender;
}

我想从一个组件中收听它:

ngOnInit() {
    this.chatter.listenForMessages().subscribe(msg => console.log(msg));
}

这给了我以下错误:

EXCEPTION: Error: Unrecognized teardown 1 added to Subscription.
Error: Unrecognized teardown 1 added to Subscription.
    at Subscriber.Subscription.add (Subscription.ts:151)
    at Observable.subscribe (Observable.ts:93)
    at LoginPage.ngOnInit (login.ts:15)
    at DebugAppView._View_LoginPage_Host0.detectChangesInternal (LoginPage.template.js:29)
    at DebugAppView.AppView.detectChanges (view.ts:261)
    at DebugAppView.detectChanges (view.ts:377)
    at DebugAppView.AppView.detectContentChildrenChanges (view.ts:280)
    at DebugAppView.AppView.detectChangesInternal (view.ts:272)
    at DebugAppView.AppView.detectChanges (view.ts:261)
    at DebugAppView.detectChanges (view.ts:377)
BrowserDomAdapter.logError @ browser_adapter.ts:82

如果 transpile tsc 或允许在浏览器中发生相同的错误,并且我以 ES6 或 ES5 为目标,则会发生相同的错误。

我已经看了好几个小时了,我在任何其他网站上都没有找到对它的引用。该错误消息来自 RxJS,它检查传递给 .subscribe() 方法的内容,检查其类型是“对象”还是“函数”,如果两者都不是,则发出此错误。我在 plunker 或预定义函数中传递了 lambda,它们会导致相同的问题。

有什么想法吗?如果我在组件中创建 Observable,那么就没有问题。如果我订阅了该服务,那么我会遇到同样的错误......所以很困惑。

【问题讨论】:

  • 也许可以:私人消息发送者:Observable;或私人消息发送者:Observable;
  • 不幸的是,这不起作用。此外,也许奇怪的是,如果您开始通过 Observable 提供值,尽管出现错误,它们确实会收到,但其他函数(最值得注意的是 Angular2 生命周期方法)不会被执行。所以订阅有效,但应用程序在之后状态不佳......

标签: typescript angular rxjs


【解决方案1】:

对于有类似错误消息的其他人。您可能没有将Object.create 传递给返回TeardownLogic 的回调函数。其中:

export type TeardownLogic = AnonymousSubscription | Function | void;

在哪里

export interface AnonymousSubscription {
  unsubscribe(): void;
}

例如,我返回的是boolean

this.showSomething = Observable.create((observer: Observer<boolean>) => this.code === "00108");

当我应该返回AnonymousSubscription时:

this.showSomething = Observable.create((observer: Observer<boolean>) => {
    observer.next(this.code === "00108");
});

【讨论】:

    【解决方案2】:

    您的问题是Array#push 返回一个数字(这是Array 的新长度),当您执行Observable.create(observer =&gt; this.clients.push(observer)) 时,它会尝试将其用作新的TeardownLogic

    我建议你不要使用 observer-array 模式,你只是在诚实地重新发明轮子,你不太可能正确地做到这一点(*注意: 不只是你,我已经看到它出现在 ng2 教程中,它只是一个糟糕的、糟糕的模式)。

    如果您需要多播行为,您应该改用Subject

    private messageSender : Subject<string>;
    
    constructor() {
        this.messageSender = new Subject<string>();
     }
    
    public listenForMessages() : any {
        console.log("Listen Requested...")
        return this.messageSender.asObservable();
    }
    

    更好的解决方案是完全取消中间 Subject 并直接订阅消息源,但在不了解您的应用程序的情况下,我实际上无法说出您如何连接它。

    【讨论】:

    • 呃!非常感谢您看到这一点,即使在单步执行代码之后,我也迷失了 1 的来源。该主题将为我工作。原始源将是一个单独的套接字,它以 JSON 形式提供不同的内容。 observable 的客户端将关心内容的子集,我想隐藏源和从客户端过滤掉内容的需要。主题在功能上和语义上看起来都是正确的。再次感谢。
    • @paulpdaniels 嗨,保罗——我在遇到同样的错误后才看到你的答案——你有什么可以提供的资源,以便我可以通过以下方式了解何时/何时不使用主题Observable> 似乎如果你返回一个 Subject 而不是 Observable 那么它基本上就像在 Angular 1 中返回一个 deferred 而不是一个 Promise。想法?
    • @Katana24 主题 API 在这里:github.com/Reactive-Extensions/RxJS/blob/master/doc/…。 Subject 是 Observable 到 Observers 之间的一对多映射(允许一个 Observable 触发多个 Observers 上的操作),我不认为 deferred 对 Promise 有这种作用(但我可能是错的)。但与 deferred 对 Promise 所做的类似,Subject 也提供了一个接口来自己触发多个 Observer 上的这些操作(即您的代码充当 Subject 的 Observable 输入)。
    【解决方案3】:

    刚刚完成@Tom 的回答,我遇到了同样的问题,因为我没有处理观察者。

    错误的实现:

    @Injectable()
    export class QuizEditorGuard implements CanDeactivate<QuizEditorPage> {
    
      constructor(private app: ApplicationService) { }
    
      canDeactivate(
        quizEditor: QuizEditorPage,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot
      ): Observable<boolean> | Promise<boolean> | boolean {
        return Observable.create((observer: Observer<boolean>) => {
          if (quizEditor && quizEditor.hasUnsavedChanges) {
            observer.next(true);
            observer.complete();
          }
          else
            return false; //here is the problem
        });
      }
    }
    

    正确实施:

    @Injectable()
    export class QuizEditorGuard implements CanDeactivate<QuizEditorPage> {
    
      constructor(private app: ApplicationService) { }
    
      canDeactivate(
        quizEditor: QuizEditorPage,
        currentRoute: ActivatedRouteSnapshot,
        currentState: RouterStateSnapshot,
        nextState: RouterStateSnapshot
      ): Observable<boolean> | Promise<boolean> | boolean {
        return Observable.create((observer: Observer<boolean>) => {
          if (quizEditor && quizEditor.hasUnsavedChanges) {
            observer.next(true);
            observer.complete();
          }
          else {
            observer.next(false); //always implement next to warn observer
            observer.complete();
          }
        });
      }
    }
    

    回到@Steven 的问题,他的错误发生的原因相同:他创建了一个观察者,但没有告诉他的对象在插入客户端后要做什么。

    Observable.create(observer => 
        this.clients.push(observer));
        observer.next("some string");
        observer.complete();
     }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-06-05
      • 2018-02-02
      • 1970-01-01
      • 2018-01-13
      • 2018-09-30
      • 2021-01-20
      • 1970-01-01
      • 2017-10-18
      相关资源
      最近更新 更多