Async/Await in JavaScript: A quick primer

If you've been following the state of the JavaScript world recently, you've probably seen people talk about async/await. But for a lot of beginners, it may be difficult to understand what it actually is.

How we got here

Asynchronous JavaScript used to use callbacks (which are simply functions passed as parameters), like this:

getDataFromServer(function (response) {

...which doesn't look too bad, but then you get into callback hell:

fs.readdir(source, function (err, files) {
  if (err) {
    console.log('Error finding files: ' + err)
  } else {
    files.forEach(function (filename, fileIndex) {
      gm(source + filename).size(function (err, values) {
        if (err) {
          console.log('Error identifying file size: ' + err)
        } else {
          console.log(filename + ' : ' + values)
          aspect = (values.width / values.height)
          widths.forEach(function (width, widthIndex) {
            height = Math.round(width / aspect)
            console.log('resizing ' + filename + 'to ' + height + 'x' + height)
            this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
              if (err) console.log('Error writing file: ' + err)

Yikes. (Also, that little snippet was courtesy of - great read!)

So then we moved onto Promises, which are basically objects where you can chain functions one by one – so you get something like this:

.then(data => process(data))

Okay, better. Let's chain a bunch

.then(data => process(data))
.then(data => displayOnScreen(data))
.then(() => processUserInput())
.then(input => sendToServer(input))
.catch(error => console.error(error))

So it looks a little better, sure. But this can still get a little crazy if not everything is asynchronous.

Meet async/await

Defining key terms

  • async - A type of function that returns a Promise, that can be used with await
  • await - Only valid inside async functions, waits for a Promise to return a value.

Let's put that example above into an async function.

async function grabAndDisplay() {
    try {
        let data = await getDataFromServer()
        await displayOnScreen(data)
        let input = await processUserInput()
    } catch (error) {

Okay, so here's what's cool about that:

  • We can use synchonous methods and calls very easily
  • The code looks much more consise
  • nothing had to be re-written (async/await just rely on Promises, after all)

So, we can call grabAndDisplay in two ways:

grabAndDisplay().then() // It's just a promise!
// or, from an async function
await grabAndDisplay()

Essentially, await "pauses" the async function (but does not block the main thread, since it's just an abstracted Promise!)

Further reading: