Image for post
Image for post

ES 5-6-7: From Callbacks to Promises to Generators to Async/await

Oct 1, 2015 · 3 min read

Let’s take a real life use case with the request library.

Step 1: Callback hell — N levels deep

This is how typical NodeJS code would look like. Every function receives a callback function with a commonly used signature:
function(err, response) { }

Step 2: Promises — 1 level deep

Promise libraries take the typical callback function:
function(err, response) { }
And split those arguments into separate then/catch chainable callbacks:
.then(function(response) { }).catch(function(err) { })

You can use Q, Bluebird or any of the innumerable promise libraries. I’ve used bluebird here. You have to first “promisify” the old-style callback library methods.

Note how you have to use “request.getAsync” instead of “request.get”. That’s called “promisification” (line #2) — it converts regular methods into promise-style methods. Also note how it simplifies the place where foo() is invoked as well.

Step 3: Promises+Generators — 0 level flat

Let’s combine the power of promises and ES6 generators.

“foo” is now almost sequential. We reduced the program from 27 lines (callback style) to 23 lines (promises) to 19 lines (promises + generators). It now appears completely flat without any nested functions. Of course, behind the scenes there are still callbacks happening, but WYSIWYG.

Note that the place where we call “foo” still uses promises. We can flatten that as well to use generators, and it becomes a simple try/catch.

And the place where you call “callerFunction” can also be flattened, and so on, and so on until the topmost entry point of the app. For web applications, that entry point is the web framework. If the web framework is aware of using generators and promises, you can basically make all your functions as generators and forever flat. And you get close to something like koa.

Transforming Tests

Generators are immensely useful in writing Tests (Mocha/etc).Tests usually have a lot of callbacks, but they run in sequence. What a waste of asynchronicity. You can write test cases today using Generators, without worrying about switching testing frameworks.

Step 4: ES7 async/await

ES7 async/await further works on top of generators. Babel already has it in enabled (though its still in staging), so you can try this today.

Wait, how does this work?

This whole magic simply works because NodeJS callbacks have a standard signature of function(err, response) { }.

Promise libraries simply act as a glue between your code, target function (request.get/post/…) and a Deferred object.

When ES6 introduced generators, Promise libraries hooked in with a nify hack: If you “yield a promise”, you’ll get the resolved value back.

How Generators work is a larger topic altogether. I recommend reading or any of the innumerable articles on the web.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store