I'm using redux-saga
to start multiple requests concurrently as described in the redux-saga docs. The all
effect has an all or nothing semantics
, similar to Promise.all
.
Only if all effects
succeed, yield all([...])
succeeds. However, I am doing several requests from which I expect some of them to fail and some of them to succeed. I would like to start all of them in parallel and consume the responses from those requests that have succeeded.
Therefore, I tried to wrap the request into a Promise
that always resolves no matter whether the request was successful or not:
// watcher saga
export function* watchMultipleRequests() {
while(true) {
const {ids} = yield take('VIDEOS_REQUEST');
yield fork(doMultipleRequests, ids);
}
}
// worker saga
export function* doMultipleRequests(ids) {
const requests = ids.map(id => {
// api.buildVideoRequest returns a promise once it is invoked
const wrapper = ignoreErrors(api.buildVideoRequest, id);
return call(wrapper);
});
try {
const responses = yield all(requests);
yield put({type: 'VIDEOS_SUCCESS', responses});
} catch (error) {
// should not happen because we are always resolving the promise
console.log(error);
}
};
export function ignoreErrors(fn, ...args) {
return function* () {
yield new Promise(function (resolve) {
return fn(...args)
.then(response => {
console.log('success = ', response);
resolve(response);
})
.catch(response => {
console.log('error = ', response);
resolve(response);
});
});
}
}
I would like to handle the error cases in the reducer
. However, if I fire n
requests, the responses
array contains n
times undefined
. Has anyone a clue on why this is not working?
The issue is that the ignoreErros function is a generator function. Implementing it like this:
export function ignoreErrors(fn, ...args) {
return () => {
const ignoreErrorCallback = (response) => response;
return fn(...args).then(ignoreErrorCallback, ignoreErrorCallback);
};
}
is sufficient.