web-dev-qa-db-ja.com

自身を参照しているサブスクライバーから「初期化前に「変数」にアクセスできません」というエラーが表示されるのはなぜですか?

私の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();
            }
        }
    });
}
_

これはほとんどの場合正しく機能しますが、次のエラーメッセージが表示されることがあります。

_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)
_

名前からわかるかもしれませんが、_abstract-content-component_はいくつかの実装を持つ親クラスであるため、これは子クラスから呼び出されますが、これは実際には、それを作成するために使用している独自のロジックを持たない空のシェルですテンプレートの切り替えが簡単。

エラーメッセージは私には無意味なようです(この場合、51行目はif(sub)チェックです。これは、の後の行に同じエラーが表示されていたため追加したものです)。独自のイベントハンドラ?他の場所でこのパターンをうまく使用していますが、なぜここに問題があるのですか?

2
glenatron

Rxjs、jetについてあまり知らなかったときにコードが古く、記述されていることを認識して、同じ問題に遭遇しました。今では、この方法でコードを記述するためのアンチパターンと見なしています。

必要なのは、1つの値を出力してから実行することです。いくつかのオプション

  1. 私がやること:

    contentService.loaded .pipe(first()、).subscribe(...);

  2. または、同じように:

    contentService.loaded .pipe(take(1)、).subscribe(...);

  3. promiseを使用します。非推奨ではなく、常に正確に1つの値が必要な場合、「Observable」のuseCaseは実際にはありません(または、文字列が必要なときに常に数値を使用して文字列を作成します)。数字が素晴らしいものだからです;)

気を付けて!

0
hogan