The Current Situation, ES6, and Beyond
Before we dive into the asynchronous functions of ES7, let’s build up by showing how we currently implement things, how it’ll change in ES6, and then show how asynchronous functions just make things even better. First off, we’re going to take a look at promises. Promises are a standard laid out in the Promises/A spec. Right now there are dozens of libraries that provide their own implementations of this spec, and most also throw some other features on top. It’s great that we have a standard, and the most important functionality is implemented the same across the board, but there are still a lot of inconsistencies between the libraries. It’d be nice if we could settle this down to a single implementation… we have! ES6 is bringing in its own implementation of promises which should take over and become the de facto way of doing things. I’m still on the fence about how I feel about the syntax, but that’s not a big issue.
Promises are great and everything, but we still like to write our code synchronously. Whether we’re using callbacks out the whazoo or replacing them with promises, it’s still harder to read than synchronous code. Well, another great ES6 feature has come to the rescue for us there: generators. Jmar777 talks about generators, giving us a quick rundown, and then goes on and tells us how he created a library that takes advantage of generators to force the code to simply wait until the asynchronous operation is finished before moving to the next line. This works really well and, for now, can be extremely useful.
Here’s an example (adapted from the async functions proposal page) of using pure promises vs using promises + Suspend (jmar777’s generator library):
// With Pure Promises
The magic here is in the
suspend(function*()... line and the
yield statement. I was blown away when I first saw that we could do this.
ES7’s Gift to the Web Developers
await keyword inside an
// With Asynchronous Functions and `await`
You must use
async on the function in order for
await to work. Also, notice that when you use
await, if the promise is resolved, it will evaluate to the value the promise was resolved with, so you can use a simple assignment like we did in the example. If the promise is rejected, it’ll throw an error, which means we can catch rejections with
catch blocks. Using the
await keyword should work with any promise, not just ones returned from another asynchronous function or an ES6 built-in promise.
When we prepend a
function declaration with
async, it’ll return a promise without you having to even touch the promise API! To resolve the promise, just return a value from the function (or don’t return any values if you want it to resolve without a value), and if you want to reject the promise, just
throw your rejection value.
If you’re like me, you might be thinking that this is awesome, but it’s not really useful because this feature isn’t available yet. Well, that’s true, but the traceur compiler actually already supports compiling this feature to ES5, so if you think adding a build step is worth the time you’ll save, I’d definitely take a look into it.
You may have noticed that the asynchronous function example looks very similar to the Suspend example, except we don’t need to require a library for it, we don’t need the wrapping
suspend function, we add the
async keyword to the front of the function declaration, and we replace
await. There’s a reason for this similarity. To quote the spec page:
Async functions are a thin sugar over generators and a spawn function which converts generators into promise objects.
In other words, while I considered the use of generators as a hack, they are still being used behind the scenes; we’re just replacing them with a cleaner and clearer syntax specifically designed for promises. The reason why
await only works inside an
async function is because the
async keyword is the signal to the translator to replace it with a
suspend function and swap all the
await keywords to
Also, keep in mind that this spec is in the very early stages, so things could change quite dramatically, though I can’t see what they’d change except maybe the keywords.
Finally, another great article about this is Jake Archibald’s article on ES7 async functions. It’s worth checking out.
I used to be excited about ES6, but now I’m more excited about ES7. Promises were supposed to be a solution to the asynchronous operation problem, but they really only solved a small subset of what we needed. I think asynchronous functions from ES7 take promises to the next level and really make asynchronous coding simpler. God Bless and Happy Coding!