为什么我从引用自身的订阅者那里收到“初始化前无法访问‘变量’”错误?

gle*_*ron 10 typescript angular angular8

在我的 Angular 8 应用程序中,我有一个订阅服务并等待服务已加载的通知的组件,如下所示:

constructor(public contentService: ContractService) {
    let self = this;
    let sub = contentService.loaded.subscribe(function(loaded) {
        if (loaded) {
            self.loading = false;
            if (sub) {
                sub.unsubscribe();
            }
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

这在大多数情况下都能正常工作,但有时我会看到以下错误消息:

ERROR ReferenceError: Cannot access 'sub' before initialization
    at SafeSubscriber._next (abstract-content.component.ts:51)
    at SafeSubscriber.__tryOrUnsub (Subscriber.js:185)
    at SafeSubscriber.next (Subscriber.js:124)
    at Subscriber._next (Subscriber.js:72)
    at Subscriber.next (Subscriber.js:49)
    at BehaviorSubject._subscribe (BehaviorSubject.js:14)
    at BehaviorSubject._trySubscribe (Observable.js:42)
    at BehaviorSubject._trySubscribe (Subject.js:81)
    at BehaviorSubject.subscribe (Observable.js:28)
    at Observable._subscribe (Observable.js:76)
Run Code Online (Sandbox Code Playgroud)

正如您可能从名称中abstract-content-component了解到的那样,这是一个具有多个实现的父类,因此它是从子类调用的,但这实际上是一个空壳,没有自己的逻辑,我正在使用它来轻松切换模板。

错误消息对我来说似乎毫无意义(在这种情况下,第 51 行是if(sub)我添加的检查,因为我在之后的行中看到了相同的错误),因为如果我们在自己的事件处理程序中,订阅怎么可能不存在?我在其他地方成功使用了这个模式,为什么这里有问题?

lea*_*iro 6

您可以通过声明sub为组件的属性来消除此错误。

sub: Subscription = new Subscription();
// ...

constructor(public contentService: ContractService) {
    let self = this;
    this.sub = contentService.loaded.subscribe(function(loaded) {
          // ...
          this.sub.unsubscribe();
          // ...
    });
}
Run Code Online (Sandbox Code Playgroud)

尽管我需要说进行此类调用的正确位置不在构造函数中。也许里面ngOnInit是个好地方。


为了确保订阅者在服务返回第一个值后不会收到任何其他值,您确实可以在其“工作”完成后取消订阅(就像您正在做的那样),但将sub变量声明为属性并使用new Subscription();


为确保您不会挂起任何订阅,您可以ngOnDestroy在组件中取消订阅:

ngOnDestroy() {
  // ...
  this.sub.unsubscribe();
  // ...
}
Run Code Online (Sandbox Code Playgroud)

此外,如果您觉得需要更好地了解Observables模式的工作原理,请参阅Angular Docs for Observables