News for hackers. Stuff that matters.
Re:Why Would Anyone Need JavaScript Generator Functions? by the_other on Monday November 07, 2022 @10:00AM (#33506626)
Redux-sagas[0] makes great use of generators. I found it a fantastic tool, if you're already in the redux ecosystem, and have an application that sprawls enough to benefit. It's great when you have to manage multiple process lifecycles. A single "saga" can summaries an entire service lifespan in just a few lines of code. Good candidates include a socket connection, a user session, analytics etc. I desperately want to use it with my current project (streaming video) but our code's too mature to introduce such an architectural change.

The downsides are:

- a quirky syntax that needs learning, and is of the "loose with semantics" style - like Rails-eque REST's play with HTTP methods

- it's hard to test (despite what the documentation claims). It's highly declarative, and such code seems hard to test.

[0] http://redux-saga.js.org/

Re:Why Would Anyone Need JavaScript Generator Functions? by isakkeyten on Monday November 07, 2022 @10:16AM (#33506861)
Be careful. You will summon acemarke with this comment.
Re:Why Would Anyone Need JavaScript Generator Functions? by acemarke on Monday November 07, 2022 @10:30AM (#33507053)
HAH! and ironically I read this literally 10 minutes after you posted it :)

dons maintainer hat

<ObligatoryResponse>

We've been generally recommending against use of sagas for years - they're a power tool, and very few apps need that. They're also a bad fit for basic data fetching.

Today, Redux Toolkit's "RTK Query" API solves the data fetching and caching use case, and the RTK "listener" middleware solves the reactive logic use case with a simpler API, smaller bundle size, and better TS support.

Resources:

- https://redux.js.org/tutorials/essentials/part-7-rtk-query-b...

- https://redux-toolkit.js.org/rtk-query/overview

- https://redux-toolkit.js.org/api/createListenerMiddleware

- https://blog.isquaredsoftware.com/2022/06/presentations-mode...

</ObligatoryResponse>

Re:Why Would Anyone Need JavaScript Generator Functions? by aastronaut on Monday November 07, 2022 @11:10AM (#33507686)
I'll use your nice response for an actual question/remark, gotcha! =)

Recently I had a look at the kubeshop-dashboard repo[1] and their use of the RTK Query API[2]. When I write the boilerplate for any SPA nowadays, I usually like to merge any fetching logic with the lib-specific notification/toast-methods, in order to render something to the user about any reached warning- or error-timeouts for each ongoing fetch by default. Meaning:

- every new fetch would start a timer

- after 10secs a warning-notification is shown "a fetch takes longer than expected..."

- and after 30secs the AbortController signals the cancelling of the ongoing fetch and an error-notification is shown "fetch took to long. click to try again."

The implementation of react-query, its "hook-yfied" nature, makes it super easy to wrap it and merge it with the component-lib to create such a thing. I just need to wrap its provided hooks (useQuery, useMutation) with "hook-creators" (I usually call them createQueryHook and createMutationHook) and don't need to dive into any of its implementation specific details. But createApi, as provided by RTK Query API, makes this quite a bit harder, or so it seems to me at least. How would you wrap createApi to provide such a functionality for every fetch by default?

[1]: https://github.com/kubeshop/testkube-dashboard

[2]: https://github.com/kubeshop/testkube-dashboard/tree/main/src...

Re:Why Would Anyone Need JavaScript Generator Functions? by acemarke on Monday November 07, 2022 @01:09PM (#33509647)
Hmm. Lenz ( @phryneas in most places) could speak more to some of this, but I don't think RTKQ really supports the idea of "canceling" a fetch in general. Can you give some specifics about what that means in your case?

As for the timers and toasts go, I can think of two possible approaches off the top of my head.

First, you could provide a custom `baseQuery` function [0] that wraps around the built-in `fetchBaseQuery`, does a `Promise.race()` or similar, and then triggers the toasts as needed.

Another could be to use the RTK "listener" middleware [1] to listen for the API's `/pending` actions being dispatched. Each pending action would kick off a listener instance that does similar timer logic, waits for the corresponding `/fulfilled` or `/rejected` action, and shows the toast if necessary .

If you could drop by the `#redux` channel in the Reactiflux Discord [2], or open up a discussion thread in the RTK repo, we could probably try to chat through use cases and offer some more specific suggestions.

[0] https://redux-toolkit.js.org/rtk-query/usage/customizing-que...

[1] https://redux-toolkit.js.org/api/createListenerMiddleware

[2] https://www.reactiflux.com

Re:Why Would Anyone Need JavaScript Generator Functions? by aastronaut on Monday November 07, 2022 @01:48PM (#33510302)
> Can you give some specifics about what that means in your case?

react-query has a default behavior to cancel a fetch when the component unmounts (AFAIK), eg. the user changes to another view and the data of the previous view aren't needed anymore. I prefer to only have those fetches pending which are actually needed and seem likely to succeed, as otherwise my SPAs would just add unnecessary load on the API gateway. I specifically had such a case when the backend team was in transition to a microservice architecture, hence the timeouts.

But thanks, will join the discord then after I created a repo to play around.

Re:Why Would Anyone Need JavaScript Generator Functions? by mcluck on Monday November 07, 2022 @01:13PM (#33509704)
What's weird is that I still firmly believe that sagas is one of the sanest ways of organizing an application. I built a sort of boilerplate project that shows how I use it[1] but the TL;DR is that I can wrap all of my functionality into nice little sagas and manage the state very easily with lenses. Handling data fetching isn't too complicated either [2] but I'm also not doing any sort of fancy caching in this example.

[1]: https://github.com/MCluck90/foal-ts-monorepo/blob/main/app/c...

[2]: https://github.com/MCluck90/foal-ts-monorepo/blob/main/app/c...

Re:Why Would Anyone Need JavaScript Generator Functions? by codelikeawolf on Monday November 07, 2022 @09:05PM (#33515138)
I'm 1000% with you on this. If you're dealing with a bunch of operations that need to happen in a very specific order, there's really nothing else out there that comes close. I'm able to look at saga code I've written months (or years!) ago and figure out what's going on in a short amount of time without having to jump around.

I used sagas pretty heavily in an app I built to transfer data between Clockify and Toggl, which required that data be fetched/loaded into state in a very specific order[1]. You can't be sagas for clarity.

[1]: https://github.com/mikerourke/transfermyti.me/blob/main/src/...

Re:Why Would Anyone Need JavaScript Generator Functions? by acemarke on Monday November 07, 2022 @09:58PM (#33515421)
Yeah, sagas can be useful - not saying they aren't.

But on the other hand, I've seen plenty of codebases and talked to lots of Redux users where sagas turned into an impenetrable spaghetti mess of actions and events going everywhere, and it was impossible to trace what was going on.

There's also a lot of additional boilerplate you need to write to use sagas. Redux's early reputation for "boilerplate" was deserved, and there's a lot of reasons why that happened - patterns shown in the docs, things like action creators and string constants, immutable updates with spread operators, etc. While they weren't _required_, sagas were definitely _a_ contributing factor to that reputation.

We've pushed to erase the "boilerplate" concerns and fix that reputation with Redux Toolkit, and so a part of that has been encouraging people to _not_ use sagas unless absolutely necessary. I wrote up a post a while back on reasons why we opted to focus on thunks instead of sagas in RTK [0], and the "Evolution of Async Logic" talk [1] (which I need to turn into a docs page) covers our recommendations today.

If sagas do work well for you, that's great! But we really do think they _aren't_ the right choice for most Redux apps and users.

[0] https://blog.isquaredsoftware.com/2020/02/blogged-answers-wh...

[1] https://blog.isquaredsoftware.com/2022/05/presentations-evol...

Re:Why Would Anyone Need JavaScript Generator Functions? by codelikeawolf on Tuesday November 08, 2022 @01:41PM (#33522607)
Agreed that sagas can turn into spaghetti and probably aren't a great choice for most Redux apps. Just like everything else in this industry, sometimes you should use stuff, sometimes you shouldn't, it depends. I did want to mention that I've been using Redux for over 6 years now and I really appreciate the improvements you and the rest of the contributors have made. Keep up the good work and thanks for being awesome!
Re:Why Would Anyone Need JavaScript Generator Functions? by pgorczak on Monday November 07, 2022 @10:09AM (#33506764)
Async generators similarly open up different ways to program complex / multi step user interactions. Instead of creating “state machine” objects that mutate on every input, you can have async functions aka coroutines that iterate over user inputs, making the flow of an interaction much more explicit.
Re:Why Would Anyone Need JavaScript Generator Functions? by qudat on Monday November 07, 2022 @12:34PM (#33509106)
> it's hard to test (despite what the documentation claims). It's highly declarative, and such code seems hard to test.

redux-saga member here. If we concede that mocks are inherently difficult to get right and maintain, often requiring libraries or testing frameworks to do a lot of the heavy lifting, then I would argue testing sagas is a breeze in comparison.

The real magic behind redux-saga and its use of generators is the end-user functions do not have side-effects at all, they merely describe what those side-effects ought to look like. The library activates the side-effects in its runtime, the end-user just yields to json objects.

So in order to test sagas, all you need is to run the generator and make sure it yields the things you expect it to yield.

https://bower.sh/simplify-testing-async-io-javascript

Having said all that, because the react world has heavily shifted towards hooks -- which explicitly make the view layer impure and hard to unit test -- a bunch of tooling has come out to prefer integration testing. In particular, testing user flows and evaluating what the user sees. In this paradigm, testing individual sagas or even react components is not nearly as valuable.

Re:Why Would Anyone Need JavaScript Generator Functions? by sktrdie on Monday November 07, 2022 @01:20PM (#33509815)
First of all, sagas are an amazing concept that I still cherish even if I don’t use them anymore (hype not there?).

Regarding the hooks comment I’m not sure I follow. Surely components are also idempotent (if you skip useEffect) and should be replayable - that’s at least how I think react refresh can manage to keep state intact during file changes in development.

Anyway I still very much value the concepts behind sagas so thanks for great work.

Re:Why Would Anyone Need JavaScript Generator Functions? by qudat on Tuesday November 08, 2022 @10:26AM (#33519999)
> Regarding the hooks comment I’m not sure I follow. Surely components are also idempotent (if you skip useEffect) and should be replayable - that’s at least how I think react refresh can manage to keep state intact during file changes in development.

We used to have the concept of smart and dumb components, with dumb components we could test if we provide X props we could determine Y result and write tests expecting Y to be true. Now with the advent of hooks, side-effects are much more likely to be in all of our components. This makes react components impure and difficult to test as individual units. This movement started primarily with the shift to hooks.

> Anyway I still very much value the concepts behind sagas so thanks for great work.

Thanks!

Re:Why Would Anyone Need JavaScript Generator Functions? by the_other on Tuesday November 08, 2022 @06:17AM (#33518012)
> redux-saga member here.

Thanks for responding!

> So in order to test sagas, all you need is to run the generator and make sure it yields the things you expect it to yield.

This was the crux of what I found frustrating, actually. A simple saga with one or two steps was ok. Longer ones were painful. My test scripts ended up with these patterns:

- looking 80% like my application code

- needing to mock almost every step (every yield's output and input) - which bifurcates quickly if your sagas branch

- requiring digging into the emitted call/take/etc payloads (which seems the opposite of what you want when using a utility - I'd prefer to "let the utility just do its job" in the tests)

- brittle tests - when I changed a saga, I usually needed to change the test, rather than being able to leave the tests alone to prove my refactor works.

None of this put me off using redux-sagas. The benefits for the application code were worth it, IMO.

Re:Why Would Anyone Need JavaScript Generator Functions? by qudat on Tuesday November 08, 2022 @10:20AM (#33519930)
Hey thanks for the thoughtful response.

I agree with everything you mentioned here. I'd love to continue to chat with you about how to make testing sagas better.

If you'd like, it would be great if we could move this convo to https://github.com/redux-saga/redux-saga/discussions/2337

Re:Why Would Anyone Need JavaScript Generator Functions? by noob_07 on Monday November 07, 2022 @01:06PM (#33509584)
The only off putting thing in redux-saga for me was the over use of verbs in the API. The `put, call, take, takeEvery, all`. That makes me somehow a little tense. I don't agree with the testing part though, We used helpers like `runSaga` method to get this done easily, also generator value can also be passed in using `generator.next(//value//)` if I remember correctly.
Re:Why Would Anyone Need JavaScript Generator Functions? by cageface on Monday November 07, 2022 @08:23PM (#33514897)
I had to rescue a saga based project that went badly off the rails and it was some of the hardest code I’ve ever had to debug in any language. Code flow was very difficult to reason about and forget about trying to use stack traces.
Re:Why Would Anyone Need JavaScript Generator Functions? by tylerchurch on Monday November 07, 2022 @08:42PM (#33514994)
Yeah I had to rescue a buggy React Native app where the devs put every backend call into sagas.

It was a pain to debug and I’ve since almost entirely ripped sagas out. It’ll be a good day when I can delete it as a dependency.