A few days ago I've stumbled across a very interesting article by Demir Selmanovic published on Toptal blog. The author goes over a brief history of asynchronous JavaScript, and compares the three existing approaches: callbacks, promises and async/await. That inspired me to think about my experience with async JavaScript because in my work I've had my share of all three approaches. Here are a few thoughts of my own on the same subject.
Generators - the missing link?
The first thing that came to mind was that the ES6 generators were omitted from the article. I understand the reasoning - it seems they never got enough popularity on their own. Based on the various reactions on social networks, I'd say that the generators by themselves require a certain way of thinking which is probably not natural for a web programmer dealing with business applications. Also, they do require some setup to solve the usual async problems. I'd still mention them, mainly because of these two reasons:
- async/await is based on combining promises and generators
- generators are an integral part of Redux Saga, a relevant package in Redux world
Cancellation as the common pain point
There is a problem shared by all three approaches - it is not possible to cancel an async function once it was called. At least not in a standard way. How does that hurt us? Let's say you are implementing an autocomplete control, and you dispatch multiple requests as the user types in new characters. What if the response for the previous request comes after the response for the last request? If you did nothing to prevent that, you will end up with wrong search results displayed. So how do we fix this? Three approaches come to mind:
- Use a library. There isn't a standard solution yet since there are trade offs in different ways to solve this problem. Bluebird is a powerful Promise polyfill which adds a lot of utility functions to Promise API, while CAF is a simpler solution, focused only on cancellation of async flows.
- Roll your own solution. Even popular frameworks like next.js handle this problem in their own way.
- Take a completely different approach and use streams. Angular uses observables by default, and they offer a built in way to cancel async operations. Just expect to read a lot and spend some time wrapping your mind around this.
Some of the presented approaches are just workarounds, so it's up to you to find an ideal solution for your specific problem. I hope this article can at least point you in the right direction :)