#angular #rxjs #angular-observable
Вопрос:
Предположим, у меня есть служба с методом, который отправляет URL-адрес до тех пор, пока не будет выполнено определенное условие. После этого он возвращает результат. Все это должно быть построено с помощью наблюдаемых объектов (чтобы их можно было легко отменить извне, поэтому никакой рекурсии с обещаниями или тому подобным).
Я попробовал это, и я ожидал, что буду звонить каждую секунду, пока не будет выполнено условие, а затем возвращать результат.
getData(): Observable<MyData> {
return this.apiService.get('/url').pipe(
map((res) => {
if (...certain condition concerning 'res') {
return res;
}
return timer(1000).pipe(
map(() => this.getData())
);
})
);
}
Если я вызову его таким образом, хотя apiService вызывается только один раз, и результат в методе подписки решается сразу и является другим наблюдаемым. Что-то определенно не так, что я делаю, но не могу понять, что именно, вероятно, при возврате отложенного рекурсивного вызова.
getData().subscribe(res => {
// res is an Observable, I expected an MyData after a delay of at least 1 second
// as the condition is guaranteed to fail the first time (for testing purposes)
})
Ответ №1:
С помощью рекурсии RxJS часто подразумевается использование expand
оператора.
В вашем случае вы могли бы попробовать что-то вроде этого
// condition is a function that returns true if a certain condition on res is met, otherwise false
const condition = (res) => {
if (...certain condition concerning 'res') {
return true;
} else {
return false
}
};
function getData() {
return this.apiService.get('/url').pipe(
// If the condition is met the Observable stream is completed with no value notified
// if instead the condition in not met, then the API call is performed again
expand((res) => {
return condition(res) ? EMPTY : this.apiService.get('/url').pipe(delay(1000));
}),
// this filter condition is optional and its use is to avoid notifying values
// until the expected one is received
filter(condition)
);
}
Вот штекблитц, который имитирует эту логику.