async/await and why it’s so great

It took a while, but it happened … I ran into a problem that async/await solved!

The problem

Before we talk about async/await, let’s talk about problems where it makes sense. Let’s say we want to do asynchronous things. Because we live in the future (or use a transpiler), we write us a Promise:

const asyncThing = new Promise((resolve, reject) => { return resolve('Tada!') })

But, eep, we need to do a couple more async things! Avoiding the nested promise anti-pattern, we’ll chain them in our then blocks. Let’s imagine we’re creating a Mad Libs style sentence, where we need a subject, a verb, and a noun (ex. “Man bites dog”). We’ll presume to have made a subject-finding promise, and I’ll write out the verb and noun promises as new Promises:

asynchronouslyGetSubject.then((subject) => {
  return new Promise((resolve) => {
    // fetch('verb-api').then()
    const verb = 'bites' // stand in for API call
    return resolve(`${subject} ${verb}`);
  })
}).then((phrase) => {
  return new Promise((resolve) => {
    // fetch('noun-api').then()
    const noun = 'dog' // stand in
    return resolve(`${phrase} ${noun}`)
  })
}).then((phrase) => {
  console.log(phrase)
})

What’s async/await?

Well that’s pretty spiffy, but there’s also another way to to it! async functions (sometimes referred to as “async/await” because of the use of the await keyword)!

async function madLibs() {
  const subject = await asyncGetSubject()
  const verb = await asyncGetVerb()
  const noun = await asyncGetNoun()
  return `${subject} ${verb} ${noun}`
}

And when we return, the value is “implicitly wrapped in Promise.resolve” (MDN)

If we pretend that we need to wait for each word before getting the next, that’s what async/await is useful for – say, if you need to create a user in a system before you assign some data to that user:

async function createAndUpdateUser(email) {
  const newUser = await createUser(email)
  doSomethingWithUser(newUser.id)
}

await is like a pause button so you can synchronize your asynchronous code. That’s pretty great! Now, let’s say we have a list of emails for which we want to do that? What’s a not-horrible way to do that?

Well, what if we combined async with Promise.all? After all, since an async function wraps the return in a resolve, that should work … right?

(it does)

function createUsers(emails) {
  return Promise.all(emails.map(async function createAndUpdateUser(email) {
    const newUser = await createUser(email)
    await doSomethingWithUser(newUser.id)
    console.log('about to return ', newUser.id)
    return newUser.id
  }))
}
createUsers(['foo@gmail.com', 'bar@ymail.com', 'baz@sharklasers.com'])

You can play with this on repl.it, which is an interesting way to see how adding/removing await keywords changes when things are printed!

I can has?

I’ve been so jazzed that cool tools like Promises and template strings work out of the box while I’m working in Node, that I was a wee bummed that async functions generally require a transpiler.

However, you can feel fairly confident in adopting, as the proposal was discussed at TC39 this summer, with implementation planned in 2017.

Or, if you update your Chrome browser (or already running 55+), you’ve got it 🙂 async/await is coming to Firefox in 2017. It’s currently available in Node behind a --harmony flag.

For more reading, here’s another article on promise anti-patterns that I found useful. PonyFoo (unsurprisingly) has a lovely article on async await.

Be Sociable, Share!

One Response to “async/await and why it’s so great”

  1. Daniel Ehrenberg December 6, 2016 at 11:06 pm #

    Please note that Node 7’s version behind the –harmony flag has big known bugs and should not be used in production.

Leave a Reply