Wie kann ich auf einem Rx Observable "warten"?

106

Ich würde gerne auf ein Observable warten können, z

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

Ein naiver Versuch führt dazu, dass die Wartezeit sofort behoben wird und die Ausführung nicht blockiert wird

Bearbeiten: Der Pseudocode für meinen vollständigen Anwendungsfall lautet:

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

Ich verstehe, dass ich den anderen Code in eine andere separate Funktion verschieben und an den Abonnement-Rückruf übergeben kann, aber ich hoffe, dass ich das vermeiden kann.

CheapSteaks
quelle
Können Sie den verbleibenden Code (den Sie auf die Quelle warten möchten) nicht in einen .subscribe()Methodenaufruf verschieben?
StriplingWarrior

Antworten:

131

Sie müssen ein Versprechen an geben await. Wandeln Sie das nächste Ereignis des Observablen in ein Versprechen um und warten Sie darauf.

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

Anmerkung bearbeiten: Diese Antwort verwendete ursprünglich .take (1), wurde jedoch in .first () geändert, wodurch das Problem vermieden wird, dass das Versprechen niemals aufgelöst wird, wenn der Stream endet, bevor ein Wert eingeht.

Macil
quelle
3
Könnten Sie anstelle von take (1) verwenden await observable.first().toPromise();?
Apricity
14
@apricity Wenn nach Abschluss keine Werte vorhanden waren, first()führt dies zur Ablehnung und take(1)zu einem ausstehenden Versprechen.
Estus Flask
6
@apricity @AgentME Eigentlich sollten Sie weder take(1)noch first()in solchen Fällen verwenden. Da Sie genau EIN Ereignis erwarten, sollten Sie verwenden, single()das eine Ausnahme auslöst, wenn mehr als 1 vorhanden ist, und keine Ausnahme auslöst, wenn keine vorhanden ist. Wenn es mehr als einen gibt, stimmt wahrscheinlich etwas in Ihrem Code- / Datenmodell usw. nicht. Wenn Sie nicht single verwenden, werden Sie am Ende willkürlich den ersten Artikel auswählen, der zurückkehrt, ohne zu warnen, dass mehr vorhanden sind. Sie müssten in Ihrem Prädikat für die vorgelagerte Datenquelle darauf achten, dass immer die gleiche Reihenfolge eingehalten wird.
Ntziolis
3
Vergessen Sie nicht den Import:import 'rxjs/add/operator/first';
Stephanie
7
Wie sollen wir das tun, nachdem toPromise () veraltet ist?
Jus10
26

Es muss wahrscheinlich sein

await observable.first().toPromise();

Wie bereits in den Kommentaren erwähnt, gibt es einen wesentlichen Unterschied zwischen take(1)und den first()Betreibern, wenn leer und vollständig beobachtbar ist.

Observable.empty().first().toPromise()wird zu einer Ablehnung führen, mit EmptyErrorder entsprechend umgegangen werden kann, da es wirklich keinen Wert gab.

Und Observable.empty().take(1).toPromise()führt zu einer Auflösung mit undefinedWert.

Estus Flask
quelle
Eigentlich take(1)wird kein ausstehendes Versprechen geben. Es wird ein Versprechen geben, das mit gelöst wurde undefined.
Johan t Hart
Danke, dass du es bemerkt hast, das ist richtig. Ich bin mir nicht sicher, warum sich der Beitrag unterschied, möglicherweise hat sich das Verhalten irgendwann geändert.
Estus Flask
8

Sie müssen awaitein Versprechen, also werden Sie verwenden wollen toPromise(). Sehen Sie diese für weitere Informationen auf toPromise().

Josh Durham
quelle
4

Wenn toPromisees für Sie veraltet ist, können Sie es verwenden, .pipe(take(1)).toPromiseaber wie Sie hier sehen können, ist es nicht veraltet.

Verwenden Sie daher bitte toPromise(RxJs 6) wie folgt:

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

async / warte Beispiel:

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

Lesen Sie hier mehr .

Und bitte entfernen Sie diese falsche Behauptung, dass sie toPromiseveraltet ist.

Emerica
quelle