web-dev-qa-db-ja.com

RxJSサブスクライブメソッド内で待機する方法

RxJSサブジェクトのサブスクライブコールバック内で、await関数でasyncを使用します。以下は、TypeScriptトランスパイラーが次のように文句を言うコード例です。

エラー:(131、21)TS2304:名前 'await'が見つかりません。

async ngOnInit() {
  this.subscriber = dateSubscription.subscribe((date: Date) => {
    let dbKey = await this._someService.saveToDatabase(someObject);
    // wait for db write to finish before evaluating the next code
    // ... some other code here
  });
}

通常、async以外の関数内でawaitを呼び出そうとすると、これが表示されます。何らかの方法でサブスクライブコールバックasyncを作成する必要がありますか、それとも間違っていますか?関数saveToDatabaseasyncであり、書き込まれたデータベースの主キーに解決されるプロミスを返します。

12
apricity

サブスクライブの匿名関数呼び出しに非同期署名を直接追加できます

 this.subscriber = dateSubscription.subscribe(async (date: Date) => {
    let dbKey = await this._someService.saveToDatabase(someObject);
    // wait for db write to finish before evaluating the next code
    // ... some other code here
  });
22
pearldiver

この問題を解決する私の方法は次のとおりです

const title = await new Promise<string>(resolve => 
  this.translate.get('MYBOOK-PAGE.PAGE_TITLE')
   .subscribe(translated => {
     resolve(translated)
   }));

ここで私がやっていることは私のオブザーバブルを約束に変えることです

注:ここで唯一の問題は、これが1回限りのショーであるということです。一度購読すると、再度アクセスできなくなります。ここで共有してくれました。

更新:一度だけ簡単に見られるのは、サブスクライバーの前でtoPromiseを使用するだけです (blog) 。したがって、上記の場合は次のようになります。

const title = await this.translate.get('MYBOOK-PAGE.PAGE_TITLE').toPromise();

3
Black Mamba

おそらく、この問題に対する更新された応答。応答を待機する同様のニーズがあり、Observable実装内でawaitまたはsetTimeout()メソッドを使用するのではなく、RxJSビルトインinterval()メソッドを使用するのがよりクリーンな方法になりましたサブスクリプションを完了します。

サービスでこれを試してください:

import { interval } from 'rxjs';
...

// inside your method
const source = interval(100);
    source.subscribe(x => {
        subject.next(CONNECTIONS_DATA);
        subject.complete();
});
return subject;

RxJS Docs: https://rxjs-dev.firebaseapp.com/guide/subject#reference-counting

誰かが最近これをやろうとしているなら、少しでも役に立てば幸いです。

1
Martin Marriott

await Observablesを直接使用することはできませんが、await a Promiseは使用できます。 observablesサブスクリプションで.toPromise()メソッドを使用するだけです。以下を考慮してください。

async ngOnInit() {
  const date = await dateSubscription.toPromise();      
  let dbKey = await this._someService.saveToDatabase(someObject);
}

awaitの約束をdateSubscriptionすると、Dateオブジェクトが渡されます。その後、実行の次の行に進むことができます。これにより、コードの読み取りがよりシーケンシャルになります。

一部の人々は、angularがngOnInitの完了を待たず、選択肢がないと考えています。指定されたJavaScripthere から得られるTypeScriptを見てください。ご覧のとおり、ngOnInitは、基礎となるステートマシン(ジェネレーター)を内部的に管理および実行するawaiterを呼び出します。 Angularはそれを制御できません。そのメソッドを呼び出すだけです。

0
David Pine

以下を試すことができます:

ngOnInit() {
  this.subscriber = dateSubscription.subscribe((date: Date) => {
      (async () => {
          let dbKey = await this._someService.saveToDatabase(someObject);
          // ... some other code here
      })();
  });
}
0
Remo H. Jansen