I'm attempting to repeat a request until the response has data using RxJS, at which point I'd like to call a success (or failure) handler, but I'm having trouble w/RxJS. Here's my current approach:
// ... redux-observable action observable
.mergeMap(() =>
fetchData()
.repeatWhen(response =>
response.takeWhile(({ data }) => !data.length)
.of(response)
)
)
.map(successFunction)
.catch(failureFunction);
Disclaimer: I'm quite new to RxJS....
I'm attempting to repeat a request until the response has data using RxJS, at which point I'd like to call a success (or failure) handler, but I'm having trouble w/RxJS. Here's my current approach:
// ... redux-observable action observable
.mergeMap(() =>
fetchData()
.repeatWhen(response =>
response.takeWhile(({ data }) => !data.length)
.of(response)
)
)
.map(successFunction)
.catch(failureFunction);
Disclaimer: I'm quite new to RxJS....
Share Improve this question edited Sep 27, 2021 at 9:47 Srdjan Pazin 1582 silver badges9 bronze badges asked Apr 13, 2017 at 19:48 seitzejseitzej 1312 silver badges7 bronze badges 1- 2 So, what is the expected behaviour and what is the actual behaviour? – user3743222 Commented Apr 13, 2017 at 20:06
3 Answers
Reset to default 6It's simpler to repeat the request on an interval, filter on its result and take one emission.
Observable.timer(0, 500)
.flatMap(() => fetchData())
.filter(r => r.data && r.data.length)
.take(1)
.timeout(10000)
http://jsbin.com/cafericore/1/edit?js,console
It sounds like you want to suppress ajax results and retry until you get the response you want. I'd do it like so:
// observable that will re-fetch each time it is subscribed
const request = Observable.defer(() => fetchData());
// each time request produces its value, check the value
// and if it is not what you want, return the request
// observable, else return an observable with the response
// use switchMap() to then subscribe to the returned
// observable.
const requestWithRetry = request.switchMap(r =>
r.data.length ? Observable.of(r) : requestWithRetry);
Empty data is not an error so first we check if the data is empty and throw an error if it is.
then retryWhen
can be used to test for this error and retry as long as it's occurring.
.mergeMap(() =>
fetchData()
.map(data => {
if (!data.length) {
throw 'no data';
}
return data;
})
.retryWhen(errors => errors.takeWhile(error => error === 'no data'))
)
.map(successFunction)
.catch(failureFunction);