Async/Await: The Hero JavaScript Deserved
Time to read: 5 minutes
Writing asynchronous code is hard. When it comes to JavaScript we rely heavily on callback functions to accomplish asynchronous tasks which can be far from intuitive. This cognitive overhead creates a barrier to entry for newcomers to programming and the language and even causes frequent heartburn for those of us who have been using the language a while.
In this post we’ll examine how a proposal for ECMAScript 2016 (ES7) can be used to improve our experience with asynchronous programming in JavaScript, making our code easier to understand and simpler to write.
The World of Today
Let’s start by taking a look at an attempt of asynchronous programming today. The following example uses the request library to make an HTTP request to the Ron Swanson Quotes API and prints the response to the console. Give it a spin by pasting the following into a file named app.js
and running npm install request
to install the dependency. If you don’t have Node.js installed you can grab it from here.
If you’ve worked with asynchronous programming in JavaScript before you might have already spotted why we’re not going to get a quote from this code. If that’s the case then high five.
Running it with node app.js
you’ll quickly see undefined
printed out.
Why does this happen?
The reason that the quote variable is undefined is because the callback function that assigns it is not called until after the call to the request function is finished. But because the request function executes asynchronously, JavaScript does not wait around for it to finish. Instead, it moves on to the next statement which returns the unassigned variable. For a great explanation on how async in JavaScript works under the hood check out this amazing talk by Philip Roberts at JSConf EU.
Synchronous code is generally easier to understand and write because everything executes in the order in which it is written. Return statements are widely used and pretty intuitive in other languages but unfortunately we’re unable to use them as much as we’d like in JavaScript because they don’t work well with JavaScript’s asynchronous nature.
So why go through the struggle of battling asynchronous code? Performance. Network requests and reading from the disk are what we call I/O (input/output) operations. In synchronous I/O execution the program blocks, sitting around and waiting for data transmission to complete. If it takes 60 seconds for a database query to finish the program is sitting around doing nothing for 60 seconds. However during an asynchronous I/O operation the program can resume normal execution and deal with the results of the I/O operation whenever they come up. This is why callback functions exist but callbacks are far more difficult to work with and grok when reading the source of an application.
Utopia
Can we get the best of both worlds – asynchronous code that lets us work with blocking operations but is also easier to read and write? The answer is yes thanks to the ES7 proposal for Asynchronous Functions (Async/Await).
When a function is declared as async
it is then able to yield execution to the calling code while it await
s for a promise to be resolved. If you’re not familiar with promises check out one of these great resources.
You can replace the code in app.js
with the following. We’ll also need to install the Babel transpiler to run it. Do so with npm install babel
. Babel will transpile our bleeding edge ES7 code into a version that is runnable in today’s environment. You can learn more about Babel here.
You can see that we are returning a promise that wraps the network request inside our new getQuote
function.
Inside the callback passed to request
we are calling the resolve
function of the promise with the body of the result.
Execute the following to run this example.
Woah. That code looks pretty cool and is close to the original attempt. It looks pretty synchronous even though it’s not.
In case you didn’t notice, Ron once said,
was printed out first despite being called after main
. This shows that we’re not blocking while waiting for the network request to complete.
Making Improvements
We can actually improve this further by adding error handling with a try/catch block. If there is an error during the request
we can then call the reject
function of the promise which will be caught as an error inside of main
. Like return statements, try/catch blocks were very underused in the past because they were hard to use correctly with asynchronous code.
Run this code again and you can see the exception get caught by changing the request URL to something like http://foo
.
Benefits
These are some pretty awesome benefits that are going to really change the way we write asynchronous JavaScript. Being able to write code that runs asynchronously, but looks synchronous and makes it easier to use common programming constructs like return and try/catch will certainly help make the language more approachable.
The best part is that we can use our new favorite feature with anything that returns a promise. Let’s take the Twilio Node.js library for example. If you haven’t used the Twilio Node.js library before you can read more about it here. You’ll also need to have a Twilio account which you can sign up for here.
Start by running npm install twilio
. Then paste the following into a file named twilio.js
and replace the fields in the lines marked // TODO
with your own credentials and numbers.
Just like we showed above with the getQuote function, we’ve marked sendTextMessage
as async
which allows it to await
the resolution of the promise returned from client.sendMessage
.
Wrapping it Up
We’ve seen how we can take advantage of a proposed ES7 feature to improve our experience writing asynchronous JavaScript.
I’m really excited for the Async/Await proposal to move forward. While we wait for that, we’re able to use Babel to take advantage of this today with anything that returns a promise. The proposal recently hit the candidate stage (stage 3) and is in need of usage and feedback.
Have a go at using it with the next awesome thing that you build and be sure to let me know on in the comments or on Twitter @eddiezane. And be sure to try Twilio’s JavaScript and Node.js Tutorials and Guides over on our documentation site.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.