In this article,by Luciano Mammino, the author of the book Node.js Design Patterns, Second Edition, we will explore async await, an innovative syntaxthat will be available in JavaScript as part of the release of ECMAScript 2017.
(For more resources related to this topic, see here.)
Callbacks, promises, and generators turn out to be the weapons at our disposal to deal with asynchronous code in JavaScript and in Node.js. As we have seen, generators are very interesting because they offer a way to actually suspend the execution of a function and resume it at a later stage. Now we can adopt this feature to write asynchronous codethatallowsdevelopers to write functions that "appear" to block at each asynchronous operation, waiting for the results before continuing with the following statement.
The problem is that generator functions are designed to deal mostly with iterators and their usage with asynchronous code feels a bit cumbersome.It might be hard to understand,leading to code that is hard to read and maintain.
But there is hope that there will be a cleaner syntax sometime in the near future. In fact, there is an interesting proposal that will be introduced with the ECMAScript 2017 specification that defines the async function's syntax.
You can read more about the current status of the async await proposal at https://tc39.github.io/ecmascript-asyncawait/.
The async function specification aims to dramatically improve the language-level model for writing asynchronous code by introducing two new keywords into the language: async and await.
To clarify how these keywords are meant to be used and why they are useful, let's see a very quick example:
const request = require('request');
function getPageHtml(url) {
return new Promise(function(resolve, reject) {
request(url, function(error, response, body) {
resolve(body);
});
});
}
async function main() {
const html = awaitgetPageHtml('http://google.com');
console.log(html);
}
main();
console.log('Loading...');
In this code,there are two functions: getPageHtml and main. The first one is a very simple function that fetches the HTML code of a remote web page given its URL. It's worth noticing that this function returns a promise.
The main function is the most interesting one because it's where the new async and await keywords are used. The first thing to notice is that the function is prefixed with the async keyword. This means that the function executes asynchronous code and allows it to use the await keyword within its body. The await keyword before the call to getPageHtml tells the JavaScript interpreter to "await" the resolution of the promise returned by getPageHtml before continuing to the next instruction. This way, the main function is internally suspended until the asynchronous code completes without blocking the normal execution of the rest of the program. In fact, we will see the string Loading… in the console and, after a moment, the HTML code of the Google landing page.
Isn't this approach much more readable and easy to understand?
Unfortunately, this proposal is not yet final, and even if it will be approved we will need to wait for the next version of the ECMAScript specification to come out and be integrated in Node.js to be able to use this new syntax natively.
So what do we do today? Just wait? No, of course not! We can already leverage async await in our code thanks to transpilers such as Babel.
Babel is a JavaScript compiler (or transpiler) that is able to convert JavaScript code into other JavaScript code using syntax transformers. Syntax transformers allowsthe use of new syntax such as ES2015, ES2016, JSX, and others to produce backward compatible equivalent code that can be executed in modernJavaScript runtimes, such as browsers or Node.js.
You can install Babel in your project using NPM with the following command:
npm install --save-dev babel-cli
We also need to install the extensions to support async await parsing and transformation:
npm install --save-dev babel-plugin-syntax-async-functions babel-plugin-transform-async-to-generator
Now let's assume we want to run our previous example (called index.js).We need to launch the following command:
node_modules/.bin/babel-node --plugins "syntax-async-functions,transform-async-to-generator" index.js
This way, we are transforming the source code in index.js on the fly, applying the transformers to support async await. This new backward compatible code is stored in memory and then executed on the fly on the Node.js runtime.
Babel can also be configured to act as a build processor that stores the generated code into files so that you can easily deploy and run the generated code.
You can read more about how to install and configure Babel on the official website at https://babeljs.io.
At this point, we should have a better understanding of the options we have to tame the asynchronous nature of JavaScript. Each one of the solutions presented has its own pros and cons. Let's summarize them in the following table:
Solutions |
Pros |
Cons |
Plain JavaScript |
|
Might require extra code and relatively complex algorithms |
Async (library) |
|
|
Promises |
|
|
Generators |
|
|
Async await |
|
It is worth mentioning that we chose to present only the most popular solutions to handle asynchronous control flow, or the ones receiving a lot of momentum, but it's good to know that there are a few more options you might want to look at, for example, Fibers (https://npmjs.org/package/fibers) and Streamline (https://npmjs.org/package/streamline).
In this article, we analyzed how Babel can be used for performing async await and how to install Babel.