Within a redux
saga I am sending a half dozen fetch requests to different systems. I want to wait until all those requests return, then do some final processing on the results.
To this end I have an array of promises
, representing each query. I could call Promise.all()
on the array, but this would cause the saga to hang, and thus all events to hang, until the promises return.
I tried creating an async promise
that called promise.all
, then using the redux-effects
Call on that promise, but this also hung.
How can I keep the async
nature of my saga while waiting for the promises to return?
Within a redux
saga I am sending a half dozen fetch requests to different systems. I want to wait until all those requests return, then do some final processing on the results.
To this end I have an array of promises
, representing each query. I could call Promise.all()
on the array, but this would cause the saga to hang, and thus all events to hang, until the promises return.
I tried creating an async promise
that called promise.all
, then using the redux-effects
Call on that promise, but this also hung.
How can I keep the async
nature of my saga while waiting for the promises to return?
- I'm not sure I'm following the question. If you need all responses back to plete the final processing, then you must wait for the responses to e back. There's no getting around that. While the saga is waiting for the responses to e back, the rest of your app will continue to receive events. The saga will hang or pause execution until all responses e back, but it won't block the js event loop. This seems obvious, so I feel like I must be missing the question. – tpdietz Commented Aug 15, 2018 at 16:41
- @tpdietz It is blocking the JS event loop for me, and that is what I would expect as behavior as well. Since doing something like calling promise.all would casue a blocking wait the saga's event won't plete (or yield). It continues executing, even though it's only executing a sleep mand, preventing other event's from running. Specifically I see actions dispatched to change sorting on my table not execute until the saga pletes when I use that approach. – dsollen Commented Aug 15, 2018 at 16:45
- This seems odd for sure. How are you invoking the saga? – tpdietz Commented Aug 15, 2018 at 16:53
2 Answers
Reset to default 14To run all request in parallel you should use the all
effect from redux-saga
. Its analogous to the Promise.all
method you referenced already.
Example:
import { fetchCustomers, fetchProducts } from './path/to/api'
import { all, call } from `redux-saga/effects`
function* mySaga() {
const { customers, products } = yield all({
customers: call(fetchCustomers),
products: call(fetchProducts)
});
// do something with results
}
This is the most straight forward way to run asynchronous operations in parallel and wait for all processes to plete. This approach will not block the javascript event loop. It will only block the remainder of the generator function from running. Other actions in other sagas, and other events (such as clicks), will still be received by your application while the requests are in flight.
Please refer to the official docs for more information.
You can do something like this
*getProductsSaga() {
while (true) {
yield take(types.GET_PRODUCTS_REQUEST);
try {
const result1 = yield call(() => getProducts1Promise());
const result2 = yield call(() => getProducts2Promise());
const result3 = yield call(() => getProducts3Promise());
const result4 = yield call(() => getProducts4Promise());
yield put({
type: types.GET_PRODUCTS_SUCCESS,
payload: [result1, result2, result3, result4] // process/bine results depending on how you want
});
} catch (error) {
yield put({
type: types.GET_PRODUCTS_FAILURE,
payload: error
});
}
}
}