JavaScript is filled with an abundance of libraries, frameworks, and acronyms that would make any conversation between two web developers sound like they are about to fly a spaceship to colonize Mars.
If you don’t believe me, check out this funny post:
How it feels to learn JavaScript in 2016
[If this post gets a high bounce rate I suggest deleting the rest of the paragraph after Mars, on account of the link]
As such writing Async JS is no different or less confusing.

In this post I’ll try to bring clarity to asynchronous code in Javascript. I’ll focus on back-end node.js code, but a lot of it also applies to the front-end.
Let’s first cover async JS mechanisms we have in Node:

  • Callbacks
  • Promises
  • Generators
  • Async / Await

I have not included things like observers, async.js and events, as they are not exactly the core of JS. For example, events rely on an async mechanism (such as callback). Many of the observer mechanisms are used mainly in front-end patterns today, and async.js is an external library which I stopped using. However if you want to learn more I suggest you look these up.


Callback functions are the most basic types of async code, and are common not only to JavaScript but to many other languages.
Callbacks are simple to understand. Callbacks are simple functions passed as arguments, that are called when the called function is finished.
JavaScript provides out of a box functions that be async.
In Node.js there is a lot more support for non-blocking async callbacks.

function callMeWhenDone() {

setTimeout(callMeWhenDone, 1000) // will call when 1 second passes
window.addEventHandler('click',callMeWhenDone, false) // will be called on window click

Node is non-blocking io by design and as async rather than have a process stand idle and wait for io operations to finish (read from disk, make http call etc), it will allow other code to run, and once finished will call your callback function:

function doLongProcessWithCallback(param1, param2, callback) {
  readFile("/path/to/file", (fileInput) => {  
      // process file
      // finished

doLongProcessWithCallback("stringInput", 34, callMeWhenDone);

Very simple and straightforward. The main problem with callbacks is that when these are all chained together, as many operations are in async, you’ll end up with loads of callbacks which is a nightmare to read, manage or follow. This is called callback hell.


JavaScript Promises are a different way to handle asynchronous code that allows for easier management of async code, yields easier code flow, and uses exceptions for errors, uniform signatures and easy composition, meaning we can chain promises together!

They are a bit like real life promises. Imagine your boss promising you a promotion next quarter. You don’t know if you’ll get it or not, and you’ll know that only in the future. Promises have three states: resolved, rejected and pending.

A promise constructor takes two parameters, reject and resolve, which will be called when the promise finishes and returns a chain-able promise object.

const doLongProcessWithPromise = new Promise(function resolve() {
}, function reject() {


This might look more complex, and for very simple situations you might be right. But let’s look at the chain-able .then and .catch (for success and failure of a promise).

.then(function (result) {
//this is called after the promise resolves,
//and the input parameter is the return value from the success

//or imagine this

As you can see this allows for chaining of promises, which creates sequential code. Sweet!

Prior to ES6 promises were supported using external libraries such as Bluebird, Q , RSVP and many others. However they are now also a part of the coding lanaguge, as promises are that important.

Promises deserve a post of their own so here is some more reading if you want to dive in and understand them better:


Generators are not designed to be an asynchronous mechanism per say. Their intent was to create an iterator-like functionality in the lanaguge; however they are often used to create cleaner looking, synchronous-like code. This is built on the fact that generators can be paused and resumed. Once again generators deserve a post of their own, so I will add additional reading links at the bottom of this section.

Generators landed in ES6, and can be created by adding a ‘*’ after the function keyword (or before, in class members):

function* generatorFunction() {
yield 'a'; //Once yield is called, the function is paused until it's called next.
yield 'b';
yield 'c';

var g = generatorFunction();"
console.log(; // output: a
console.log(; // output: b
console.log(; // output: c

The nice thing about generators is that inside a generator function you can pass the control to another generator *yield or to a promise / value with yield:

function * generatorFunction() {
const userInfo = yield getUserReturningPromise();
const orderInfo = yield* getOrdersForUserGenerator(userInfo);
return orderInfo;

//wraps the generator with a promise and can now be used as a promise.
const generatorFunctionTurnedIntoPromise = Promise.coroutine(generatorFunction);

As you can see you can the code becomes simpler. You can even wrap a generator into a promise easily with a co-routine (Bluebird has a co-routine, for example).
As you can see, promises and generators co-exist nicely!

Here is some further reading, if generators are still not clear:

Async / Await

Async/Await is not part of ES6 sadly, but only ES7. The use of generators and promises, while nice, is not very clean. It requires a lot of wrapping, and the intent of generators was to provide an iterator, not an async mechanism. This is where async / await shines, as it is a cleaner way to handle promises and asyncronous code in a sequential manner:

All you have to do is define an async function (with the async keyword), then enter an await keyword from your promises, much like the generator yield, but with less mess:

async function doProcess() {
const userInfo = await getUserReturningPromise();
const orderInfo = await getOrdersForUserPromise(userInfo);
return orderInfo;

As you can see the code is clean, but didn’t require any wrapping, or using generators. Adding just two more keywords allows us to use promises everywhere (promises tend to be faster than generators).

Further reading: