3 ms·
Both promises and async/await (basivally just a syntactic sugar for promises) are pretty unpleasant to use in a more complex app. It's too low-level and hard t
by megous 7y ago
Both promises and async/await (basivally just a syntactic sugar for promises) are pretty unpleasant to use in a more complex app.
It's too low-level and hard to manage (if you care about correctness and performance). You eventually have to invent your own locking (to enforce ordering guarantees between read/update remote calls) and do resource management by hand (async task becomes something you have to keep track of, in case you need to abort/restart it, recover from network errors, etc.)
There are much better abstractions for getting remote data. State machines are one such abstraction that I like to use.
I'm still awaiting the day when web devs rediscover that coding an event driven FSM with pure functions is acctually the most flexible and easiest to reason about way to manage client-server communication. Meanwhile it's my secret sauce.
- kilburn 7y agoAren't reducer-based stores (redux, useReducer) effectively "FSMs with pure functions"? These have been quite popular since very early in React's history. Am I missing something?
- megous 7y agoYes, but those don't help manage async fetch jobs.
- manigandham 7y agoState machines is what async/await and promises are. They're higher-level constructs built on the concept of iterators (with yield/generator being the lower-level), and the async syntax was designed for easy code flow without having to think about callbacks. There's no reason why these frameworks have to treat async functions as a special case. If the promise hasn't resolved then don't render that node. The fact that it was ever blocking is just a byproduct of sync-only thinking. This is extremely common in JS where libraries are designed around sync first and have workarounds to support async.
- megous 7y agoThat may be an implementation detail, but to a programmer, promises and thus async/await are just a resource that represents some background operation with some side effect attached to some undetermined time in the future when the promise settles, if ever. You get a reference to it and it's a resource to manage manually. You need to ensure that the side effect you attached to it at one time will not mess up anything in the future, despite not knowing in what situatuion in the future it will be resolving. User might have done many other operations with tha app in the meantime, etc. You may also want to carry around an AbortController, in case you may need to cancel the operation behind the promise (like a fetch). So promises are just references to some resources. Async functions actually make the management of async jobs harder, since you're basically encoding a sequence of jobs into the structure of the functions you define and you don't even see the promises behind those, and you'll not have control over their execution from the outside, unless you explicitly code for it at every point. You don't get to say: ok, whatever's going on now with all my data fetching async functions that may be currently running, I want to pause them in whatever state they may be now. Or cancel them right now, or restart them from where I paused them. With explicitely coded FSM, you can do any of this, easily.