JavaScript has always had problems with having 8-indent deep nested functions due to its lack of good async support but in ES7, that has finally come to a change! I am surprised at how unpopular this is, but it seriously deserves some more attention so I thought I’d write about it

But before you get all excited, make sure you’re transpiling with something like babel. Native support is scarce so you’ll need to run this through a transpiler to get browser-friendly code. AFAIK, Node doesn’t have much support yet either.

Already transpiling? Then you’re good to go. Additionally if you’re familiar with generators these new keywords should come naturally to you


What is this?

So they are two new keywords: async and await. Here’s an example snippet:

async function ByeByeCallbackHell(arg) {
    let Response = await doAsyncThing(arg);
    return Response;
}

ByeByeCallbackHell("special argument");

Uh… what? Hopefully I didn’t lose you but the above demonstrates how async/await works. I’ll explain this…

General Usage

You can use it by adding async before the function keyword when creating a function. Basically async & await are based of promises. You could even consider them semantic & syntax sugar for longer promise syntax.

Important bit:await can only be used in a function declared with async

Exactly how can I use it?

Everything I’ve seen on the internet describing these give horrible vague examples so you have no idea how to exactly implement it in your own code. Essentially await waits for a promise to resolve or successfully complete. If it rejects or errors, it will… well… error. So here’s a full example:

const fs = require("fs");

// Here's our async function
// which we can use with await
async function ReadFile(filename) {
    return new Promise(
        (resolve, reject) => fs.readFile(filename,
            (error, data) => error ? reject(error) : resolve(data)
        )
    );
}

This is a function we can use with await as it returns a promise. If it gets resolved, we will be able to assign the argument passed to resolve (in this case data), and do stuff with it, if it errors, we can catch that in a try..catch block.

So you can use your previous function like this:

// Example function
async function ParseAJson() {
    try {
        // Calls our async function
        let data = await ReadFile("path/to/file.json");

        let result = JSON.parse(data);
        return Promise.resolve(result); // I'll expand more on this
    } catch(error) {
        // Promise was rejected
        throw error;
    }
}

If you have previous JS experience and have been paying attention, you should understand how this works, but what’s up with the Promise.resolve? Well remember this is a async function. In an async function you should return a promise. Why? this is because this is an asynchronous function, meaning in order to be able to continue the async chain, you should wrap the value in a promise. Promise.resolve(foo) is roughly equivalent to:

new Promise(resolve => resolve(foo));

Conclusion

Questions? Leave a comment! Make sure you’ve read the Promise docs if you’re confused on Promises.