Come posso "attendere" su un osservabile Rx?


107

Mi piacerebbe poter attendere su un osservabile, ad es

const source = Rx.Observable.create(/* ... */)
//...
await source;

Un tentativo ingenuo fa sì che l'attesa si risolva immediatamente e non blocchi l'esecuzione

Modifica: lo pseudocodice per il mio caso d'uso previsto è:

if (condition) {
  await observable;
}
// a bunch of other code

Capisco che posso spostare l'altro codice in un'altra funzione separata e passarlo alla richiamata di sottoscrizione, ma spero di essere in grado di evitarlo.


Non puoi spostare il codice rimanente (che desideri attendere per la sorgente) in una .subscribe()chiamata al metodo?
StriplingWarrior

Risposte:


133

Devi passare una promessa a await. Converti il ​​prossimo evento dell'osservabile in una promessa e attendi.

if (condition) {
  await observable.first().toPromise();
}

Nota di modifica: questa risposta originariamente utilizzava .take (1) ma è stata modificata per utilizzare .first () che evita che il problema della promessa non si risolva mai se lo stream termina prima che venga visualizzato un valore.


3
Invece di prendere (1) potresti usare await observable.first().toPromise();?
apricity

14
@apricity Se non c'erano valori al termine, il first()risultato sarà il rifiuto e la take(1)promessa in sospeso.
Estus Flask

6
@apricity @AgentME In realtà NON dovresti usare né take(1)first()in casi come questo. Dal momento che ti aspetti che accada esattamente UN evento, dovresti usare single()che genererà un'eccezione se ce n'è più di 1, senza lanciare un'eccezione quando non ce n'è. Se ce n'è più di uno, probabilmente c'è qualcosa che non va nel tuo codice / modello di dati ecc. Se non usi single finirai per scegliere arbitrariamente il primo articolo che ritorna senza avvertire che ce ne sono di più. Dovresti fare attenzione nel tuo predicato sull'origine dati a monte per mantenere sempre lo stesso ordine.
ntziolis

3
Non dimenticare l'importazione:import 'rxjs/add/operator/first';
Stephanie

7
Ora che toPromise () è deprecato, come dovremmo farlo?
Jus10

26

Probabilmente deve esserlo

await observable.first().toPromise();

Come è stato notato in precedenza nei commenti, esiste una differenza sostanziale tra gli operatori take(1)e first()quando è osservabile vuoto completato.

Observable.empty().first().toPromise()risulterà in un rifiuto EmptyErrorche può essere gestito di conseguenza, perché non c'era davvero alcun valore.

E Observable.empty().take(1).toPromise()si tradurrà in una risoluzione con undefinedvalore.


In realtà take(1)sarà non produrrà una promessa in attesa. Produrrà una promessa risolta con undefined.
Johan t Hart

Grazie per aver notato, è corretto. Non sono sicuro del motivo per cui il post fosse diverso, forse il comportamento è cambiato ad un certo punto.
Estus Flask

8

Avrai bisogno di awaituna promessa, quindi vorrai usare toPromise(). Vedi questo per maggiori dettagli su toPromise().


4

Se toPromiseè deprecato per te, puoi usarlo .pipe(take(1)).toPromisema come puoi vedere qui non è deprecato.

Quindi, per favore, usa toPromise(RxJs 6) come detto:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = sample('First Example')
  .toPromise()
  //output: 'First Example'
  .then(result => {
    console.log('From Promise:', result);
  });

esempio async / await:

//return basic observable
const sample = val => Rx.Observable.of(val).delay(5000);
//convert basic observable to promise
const example = await sample('First Example').toPromise()
// output: 'First Example'
console.log('From Promise:', result);

Leggi di più qui .

E per favore rimuovi questa affermazione sbagliata che dice che toPromiseè deprecata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.