async/await in JavaScript in Five Minutes

When I first heard about async/await in JavaScript I was quite excited. Now I know about it I'm not. Let me explain; instead of doing some Lisp this evening I decided to find out what async/await fuss was about, and I think I can put it in a single sentence.

async/await is syntactic sugar to make Promises look more sequential

That's it. If you have the most basic understanding of Promises in JavaScript then you should be able to use async/await in about thirty seconds. There is nothing surprising here, which is a relief.

async

Think of this as an annotation to a function - a way of saying that, within this lexically scoped block, we'll be living in async/await world.

async function asyncAwaitLand () {
 // blah blah fishcakes
}

await

In async/await world, .then() is spelt await. And it's another annotation, this time to to an expression. What larks. Here it is in Promise-speak:

function normalPromiseLand () {
    Promise.resolve('some value')
        .then(theResultOfAPromise => console.log(theResultOfAPromise))
}

And here's the same thing in nuspeak async/await

async function asyncAwaitLand () {
 const theResultOfAPromise = await Promise.resolve('some value')
 console.log(theResultOfAPromise)
}

Playing nicely with Promises

async functions return Promises, so if you want to start chaining them all together be my guest:

const arrowAsync = async () => {
    return 'the async annotation works with anonymous arrow functions too'
}

arrowAsync()
    .then(string => console.log(string))

Errors and Rejects

But how do you .catch() those long-awaited Promises when they go horribly wrong? Would it surprise you at all if I told you that you just use the normal sequential JavaScript error handling construct of try/catch?

function rejectedPromise () {
    return Promise.reject(new Error('boom'))
}

async function asyncAwaitLand () {
    try {
        const nope = await rejectedPromise()
        console.log('will never happen', nope)
    } catch (error) {
        console.log('I caught a rejected Promise:', error.message)
    }
}

So how do you reject() in an async function? You can guess right? You just throw like it's sequential code.

async function throwingAsync () {
    throw new Error('boom')
}

function promiseLand () {
    throwingAsync()
        .then(nope => console.log('will never happen', nope))
        .catch(error => console.log('I caught an async throw:', error.message))
}

Are you still reading this?

async/await is boring - thank goodness. A pretty piece of syntactic sugaring that extends the language not one jot. If you understand Promises then you should already have some ideas for how you're going to use it - more of a way of tidying up some ugly looking bits of code than a complete rethink of your codebase.

If you don't understand Promises - stop reading articles about async/await and start reading articles about Promises.