Як я можу "чекати" на Rx-спостережуваному?


106

Мені б хотілося чекати спостережуваного, наприклад

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

Наївна спроба призводить до негайного вирішення негайно і не блокування виконання

Редагувати: Псевдокод для мого повного випадку використання:

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

Я розумію, що я можу перенести інший код в іншу окрему функцію і передати його в зворотний виклик підписки, але сподіваюся, що зможу цього уникнути.


Чи не можете ви перемістити решту коду (який потрібно чекати на джерело) у .subscribe()виклик методу?
StriplingWarrior

Відповіді:


133

Ви повинні виконати обіцянку await. Перетворіть наступну подію спостережуваного в обіцянку і чекайте цього.

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

Редагувати примітку: Спочатку ця відповідь використовувалася .take (1), але була змінена на .first (), що дозволяє уникнути вирішення питання, коли Обіцянка ніколи не вирішується, якщо потік закінчується до того, як значення пройде через.


3
Замість take (1) ви могли б використовувати await observable.first().toPromise();?
абрикос

14
@apricity Якщо після завершення не було значень, first()це призведе до відхилення та take(1)призведе до очікування, що очікує на очікування.
колба Есту

6
@apricity @AgentME Насправді НЕ слід вживати take(1)ані first()таких випадків, ані таких. Оскільки ви очікуєте, що відбудеться саме ОДНА подія, вам слід скористатись тим, single()що викине виняток, якщо їх більше ніж 1, при цьому не викидайте виняток, коли його немає. Якщо їх більше, можливо, у вашому коді / моделі даних щось не так Вам доведеться подбати про свій предикат у джерелі даних вище, щоб завжди підтримувати той самий порядок.
ntziolis

3
Не забувайте про імпорт:import 'rxjs/add/operator/first';
Стефанія

7
Тепер, коли toPromise () застаріло, як нам це зробити?
липня

26

Це, мабуть, має бути

await observable.first().toPromise();

Як було відзначено в коментарях перш, є істотна різниця між take(1)і first()операторами , коли порожньо завершено спостережуваним.

Observable.empty().first().toPromise()це призведе до відхилення, з EmptyErrorцим можна впоратись відповідно, оскільки це дійсно не було значення.

І Observable.empty().take(1).toPromise()призведе до вирішення undefinedзначення.


На насправді take(1)буде НЕ давати відкладене обіцянку. Це дасть обіцянку, вирішену з undefined.
Йохан т Харт

Дякую, що помітили, це правильно. Я не впевнений, чому пост відрізнявся, можливо, поведінка змінилася в якийсь момент.
колба Естуса

8

Вам знадобиться awaitобіцянка, тому ви захочете скористатися toPromise(). Детальніше про це див. На toPromise().


4

Якщо toPromiseдля вас застаріле, ви можете використовувати, .pipe(take(1)).toPromiseале як ви бачите тут, це не застаріло.

Тому, будь ласка, використовуйте juste toPromise(RxJs 6), як сказано:

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

приклад асинхронізації / очікування:

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

Детальніше читайте тут .

І , будь ласка , видаліть це неправильно претензії вислів toPromiseє застарілим.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.