Learning to work in a single-threaded environment
The earliest and most straightforward solution to being stuck in the synchronous world is using asynchronous callbacks (think
Let’s use a database request as an example: asynchronous callbacks allow you to invoke a callback function which sends a database request (and any other nested callbacks) off to your app, where it waits for a response from the database, freeing up the rest of your code to continue running.
Once the database request completes, the results (and any other nested code) are sent to the queue and then processed through the event loop.
In the diagram here, you can see how this differs from the synchronous code. Function C, along with E, F and G are all sent off to the browser, queue and event loop.
While this is a great solution, it leaves something to be desired. Since you can’t predict exactly when function C will resolve, you have to nest all dependent functions within it. This gets messy fast and leads to the infamous callback hell that no one wants to deal with. It was this environment that inspired the promise.
In order to deal with callback hell, libraries like Bluebird or Q allowed programmers to clean up their syntax and write code that operated asynchronously but looked synchronous. This resulted in code that was easier to read and faster to run.
With a promise, instead of bundling all dependencies into one code block and sending the entire thing off to the browser, we’re able to separate them out.
We can send the asynchronous callback (Function C) to the browser and use
.then() to hold all other dependencies (E, F, and G) aside, running them only once Function C returns and runs.
This allows us to code in a more modular, readable way, while still gaining the benefits of asynchronous programming.
Promises were fantastic — so fantastic, in fact, that ES6 brought them into the language as a standard. But using promises still left asynchronous code feeling slightly wonky, so we now have the beautiful and stunning Async/Await to help us out!
There are entire blog posts and (I’m sure) books written about Async/Await, so I’m not going to go into it in too much depth, but suffice it to say that Async/Await allows you to:
- Continue using promises
- Write asynchronous code that looks and feels synchronous
- Cleans up your syntax and makes your code more human-readable
Here are some of my favorite blog posts and videos on Async/Await, if you’re looking for more reading:
In case you missed it, Node now supports async/await out of the box since version 7.6. If you haven’t tried it yet…
Await and Async Explained with Diagrams and Examples
Thanks for reading! Cat tax: