Как подождать внутри метода подписки RxJS
Внутри объекта RxJS подписывается обратный вызов, я хочу await
в функции async
. Ниже приведен пример кода, который транспилер typescript жалуется на высказывание:
Ошибка: (131, 21) TS2304: Не удается найти имя "ожидание".
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
. Должен ли я каким-то образом сделать обратный вызов subscribe async
, или я собираюсь сделать это неправильно? Функция saveToDatabase
равна async
и возвращает обещание, разрешающее первичный ключ базы данных, который был записан.
Ответы
Ответ 1
Вам не нужно использовать await
или конвертировать Promise
в Observable
.
CF это Tweet от Бен Леша:
![enter image description here]()
Вот пример с макетом для функции saveToDatabase
:
(и рабочий 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();
Вывод:
![enter image description here]()
Ответ 2
вы можете просто добавить асинхронную подпись к анонимному вызову функции в подписке
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
});
Ответ 3
Вот мой метод решения этой проблемы
const title = await new Promise<string>(resolve =>
this.translate.get('MYBOOK-PAGE.PAGE_TITLE')
.subscribe(translated => {
resolve(translated)
}));
Вот что я делаю, меняю Обязательное на Обещание
Примечание: здесь единственная проблема в том, что это одноразовое шоу, т.е. если вы подпишитесь, как только вы не сможете получить к нему доступ снова. Подходит мне так делиться здесь.
Обновление:
Обещанные легко на одно время обещания просто использовать toPromise
перед подписчиком (блог). Так что для приведенного выше случая это будет так:
const title = await this.translate.get('MYBOOK-PAGE.PAGE_TITLE').toPromise();
Ответ 4
Вы можете попробовать следующее:
ngOnInit() {
this.subscriber = dateSubscription.subscribe((date: Date) => {
(async () => {
let dbKey = await this._someService.saveToDatabase(someObject);
// ... some other code here
})();
});
}
Ответ 5
Возможно, обновленный ответ на эту проблему. У меня была аналогичная необходимость ждать ответов, и вместо того, чтобы использовать метод await
или setTimeout() внутри реализации Observable, теперь более чистым способом является использование встроенного метода 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:
https://rxjs-dev.firebaseapp.com/guide/subject#reference-counting
Надеюсь, немного полезно, если кто-то пытается сделать это в последнее время.
Ответ 6
Вы не можете await
Наблюдаемые напрямую, однако вы можете await
a Promise
. Вы можете просто использовать метод .toPromise()
для подписки на наблюдаемые. Рассмотрим следующее:
async ngOnInit() {
const date = await dateSubscription.toPromise();
let dbKey = await this._someService.saveToDatabase(someObject);
}
Когда вы await
обещаете dateSubscription
, вам будет передан объект Date
. Затем вы можете продолжить следующую строку выполнения, что делает чтение кода более последовательным.
Некоторые люди думают, что angular не будет ждать завершения ngOnInit
, у него нет выбора. Взгляните на полученный JavaScript
из данного TypeScript
здесь. Как вы можете видеть, ngOnInit
будет вызывать awaiter, который внутренне управляет и выполняет базовую машину состояний (генератор). angular не имеет никакого контроля над этим. Он просто хочет, чтобы этот метод вызывался.
Ответ 7
async ngOnInit() { }
- некорректная подпись, так как Angular определяет интерфейс OnInit
. Он должен возвращать void
:
export interface OnInit { ngOnInit(): void; }
Если у вас есть какие-либо обещания для обработки после dateSubscription
, вы можете использовать Observable.fromPromise
как
dateSubscription
.flatMap(x=>
Observable.defer(Observable.fromObservable(this._someService.saveToDatabase(someObject)))
).subscribe()