Should I always use redux-saga `call` effect for functions that return promise?
Asked Answered
A

2

5

Assuming I have a function

function* request(url) {
   return global.fetch(url).then(response =>
     _.result(response, 'json'))
}

Both code examples work fine to me

const {data} = yield call(request, 'http://example.com/api');
yield put(actionSuccess(data));

and

const {data} = yield request('http://example.com/api');
yield put(actionSuccess(data));

Therefore the question. What is an advantage of using the call effect for functions that return promises?

Actino answered 24/11, 2018 at 23:0 Comment(0)
H
12

Some benefits of using call():

  1. Testability, the only benefit the docs seem to mention (lower half of the page). I recommend redux-saga-test-plan, it allows to mock call() and other effects by directly supplying the return value.
  2. More fine-grained task cancellation. Sagas are ES6 generators, which only yield control (back to redux-saga middleware) when you use the yield statement. These are the only points where cancellation can happen. A yield call() gives redux-saga an opportunity to cancel the task right before it's about to make that no longer needed call. Task cancellation is performed using gen.return() generator method. [1] [2]
  3. More fine-grained task scheduling in general. Redux-saga's concurrency model is basically cooperative multitasking. And JavaScript is single-threaded. A So when you yield, it's the only opportunity for redux-saga middleware to do any kind of scheduling other tasks. (I'm not sure how good redux-saga is at this, though.)

For more information, I think it's best to open an issue on redux-saga's Github to ask the maintainer directly.

UPD: As this answer is getting attention: think twice before using redux-saga. It provides:

  • A now obsolete generator-based version of async/await available since ES7
  • CSP (channels) Golang users should be familiar with
  • Task cancellation (but you cannot wait for your "cleanup" block to terminate!)

If you want to use Redux, I recommend opting for something simpler, like async thunks. You can have channels with async-csp and proper cancellation with cancellationtoken.

Hamo answered 25/11, 2018 at 14:7 Comment(2)
Yeah, makes sense only if unit tests runner walks through saga generator step by step. Although if SagaTester approach is used, when a saga is executed natively during unit test, having call doesn't bring any value.Actino
Although for task cancellation and cleanup I assumed they needed the power of generators to allow the middleware to orchestrate? The redux-saga site claims: "(kind of like async/await, but generators have a few more awesome features we need)".Okechuku
U
2

The advantage is visibility into what is going on in the app.

You want to know when, why and how the state is updated [1].

call [2] triggers an effect when a saga monitor is configured on the saga middleware before running the effect and after the effect is resolved.

With a saga monitor configured and without using call effect, I see this in the monitor logs.

Without call

However with call effect,

With call

Utility answered 24/11, 2018 at 23:40 Comment(3)
Using yield request will make sure that the promise is canceled if the parent saga is canceled. I went through debugging and got my breakpoint stoped in resolvePromise of redux-saga.Actino
I used "saga-monitor" to see if there is any difference in the debug trace information we get from using or not using call. In fact, there is almost no difference. This is the trace line with using call: effectTriggered {effectId: 11, parentEffectId: 10, label: "", effect: request} and this is without effectTriggered {effectId: 11, parentEffectId: 10, label: "", effect: {...}} Basically, I am losing the request function name in logs, but it could be sacrificed due to increased code readability.Actino
Thanks for your feedback. You're correct that the put is used for dispatch actions to store. Other effects are sent to the saga middleware. I took a look using the saga-monitor-example and yes, the function name is unknown in the log. I'll update my answer to reflect my current findings about this matter.Utility

© 2022 - 2024 — McMap. All rights reserved.