I want to call another saga from a saga.
The saga is of course a generator function, and is asynchronous.
Should I ever user yield *
or should I always use yield
?
function* mySaga({ payload: { id, name } }) {
yield myOtherAsyncSaga(); // when to use yield *?
}
I want to call another saga from a saga.
The saga is of course a generator function, and is asynchronous.
Should I ever user yield *
or should I always use yield
?
function* mySaga({ payload: { id, name } }) {
yield myOtherAsyncSaga(); // when to use yield *?
}
Share
Improve this question
asked Nov 28, 2017 at 14:16
Ben AstonBen Aston
55.7k69 gold badges220 silver badges349 bronze badges
5
|
2 Answers
Reset to default 10The saga is of course a generator function, and is asynchronous.
Should I ever user yield * or should I always use yield?
To completely answer this question, it's first necessary to understand how sagas, middlewares, process manager and generator functions generally work. In fact redux-saga
implements two sides: middleware for redux store, which intercepts and injects custom actions, and async process manager, which has own tick callback domain and helps with perform async action.
Next, every client-implemented saga function is just effect creator. In fact client saga function is implemented such way, that it actually does not do anything, but effect creation - call
, take
, put
, etc. Also, saga is not sync or async by nature - it just delegates some behavior to saga process manager, and it perform requested actions - for example, waiting promise.
Of course, you can manually perform promise/async handling in client saga, but such actions will fall from saga event cycle.
So, redux-saga
internals wants from client saga just to be an iterator, which returns appropriate effects and maybe store some information in closure activation context - in case of while(true)
- like saga processes. So, there is no use case in redux-saga
, where yield *
is mandatory, since yield *
is just re-delegation of subsequent iterator to upper level.
TLDR: always use yield*
for performance and correct type resolution in TS
If you are on JS land, yield
gives the middleware a Generator and the middleware will automatically iterate it. If you use yield*
, you are iterating the generator and yielding all the items to the middleware.
There is no big difference in this case, except that hitting the middleware is slower.
When using TypeScript, things change a bit: yield
means that the iteration of the generator will happen in the middleware and because of that our types will be incorrect. If instead we use yield*
, the iteration will happen on our scope and TS will be able to detect the proper types.
There is a small TS library that illustrates this better: https://www.npmjs.com/package/typed-redux-saga
mySaga()
generator will return just one result from the other generator, and then it'll be done. The point ofyield *
is to effectively delegate to the other generator, and continue to return all its results until it's done. The delegating generator can yield its own values before and after that. – Pointy Commented Nov 28, 2017 at 14:21yield
is behaviourally the same asyield *
if the generator only returns a single result? – Ben Aston Commented Nov 28, 2017 at 14:23yield
would be identical toyield*
in Redux, sinceyield
will yield out the iterator, and Redux magic will make it work, just like if you have yielded out a promise.yield*
just means you handle the iterator yourself, right there, whileyield
lets Redux handle it for you. – geon Commented Feb 21, 2020 at 8:17