web-dev-qa-db-fra.com

Comment attendre dans la méthode d'abonnement RxJS

À l'intérieur du rappel d'abonnement d'un sujet RxJS, je souhaite await sur une fonction async. Vous trouverez ci-dessous un exemple de code que le transpiler TypeScript se plaint d'avoir à dire: 

Erreur: (131, 21) TS2304: Impossible de trouver le nom 'wait'.

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
  });
}

Habituellement, je vois cela lorsque j'essaie d'appeler une attente dans une fonction non async. Dois-je en quelque sorte faire le rappel de souscription async ou est-ce que je me trompe? La fonction saveToDatabase est async et renvoie une promesse résolue à la clé primaire de la base de données dans laquelle elle a été écrite.

9
apricity

Vous n'avez pas besoin d'utiliser await, ni de convertir votre Promise en Observable.


CF this Tweet de Ben Lesh: 

 enter image description here


Voici un exemple avec une maquette pour la fonction saveToDatabase:
(et le serveur Plunkr: https://plnkr.co/edit/7SDLvRS2aTw9gYWdIznS?p=preview )

const { Observable } = Rx;

const saveToDatabase = (date) =>
  new Promise(resolve =>
    setTimeout(() =>
      resolve(`${date} has been saved to the database`),
      1000));

const date$ = Observable.of(new Date()).delay(1000);

date$
  .do(x => console.log(`date received, trying to save it to database ...`))
  .switchMap(date => saveToDatabase(date))
  .do(console.log)
  .subscribe();

Sortie:
 enter image description here

7
maxime1992

vous pouvez simplement ajouter directement une signature asynchrone à l'appel de fonction anonyme de Subscribe

 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
  });
17
pearldiver

Voici ma méthode pour résoudre ce problème

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

Voici ce que je fais est en train de changer mon observable en une promesse

Remarque: Le seul problème est qu’il s’agit d’un spectacle unique. si tu abonnez-vous une fois que vous ne pourrez plus y accéder. Convient à moi pour partager ici.

1
Black Mamba

Vous ne pouvez pas await Observables directement, mais vous pouvez await a Promise. Vous pouvez simplement utiliser la méthode .toPromise() sur l'abonnement observables. Considérer ce qui suit:

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

Lorsque vous await la promesse de dateSubscription, un objet Date vous sera remis. Vous pouvez ensuite continuer avec la ligne suivante de votre exécution, ce qui rend la lecture de votre code plus séquentielle. 

Certaines personnes pensent que l'angulaire n'attendra pas que la ngOnInit soit complète, elle n'a pas le choix. Jetez un coup d’œil à la JavaScript résultante de la TypeScriptici . Comme vous pouvez le constater, la ngOnInit invoquera l'attendeur qui gère et exécute en interne la machine à états sous-jacente (générateur). Angular n'a aucun contrôle sur ça. Il veut simplement que cette méthode soit invoquée.

0
David Pine

Vous pouvez essayer ce qui suit:

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