Async/Await

Better handling of Async code in JS

Introduction

The async and await keywords aren't so much a competitor to the things we use to deal with Asynchronous code in JS currently (Promises and callbacks). They are actual syntactic sugar over Promises. They allow use to have much cleaner syntax when dealing with Promises. They also make our code much more readable. Let's take a look:


Example with Promises

Let's take a look at a common example that we might see inside of a controller environment:

class UserController {
  static getUsersAndPosts(req, res, next) {
    getUsers().then(users => {
      getPosts().then(posts => {
        res.render("users", { users: users, posts: posts })
      })
    })
  }
}

This code will retrieve all users from our database environment. Then pass those users to an anonymous function. Then retrieve all posts from the db and pass it to another anonymous function. Then finally, render the users template and pass the users object and the posts object.

This code works. But, it's pretty ugly... Let's just make it pretty!


Example with Async/Await

Now, we're going to do the exact same thing, but use the async and await keywords this time:

class UserController {
  static async getUsersAndPosts(req, res, next) {
    const users = await getUsers()
    const posts = await getPosts()
    res.render("users", { users: users, posts: posts })
  }
}

So. Much. Cleaner.


async

Let's talk about what each of these keywords do. async and await only work together. You can't use them by themselves as they won't do anything. async is applied when you declare a function. This tells your application that there will be asynchronous operations inside of that function. Let's see some more examples:

async function getUsers() {
  // ...
}

const getPosts = async () => {
  // ...
}

const songTitlesByAlbum = album.songs.map(async song => {
  return await getSongTitle(song)
})

The async keyword can be applied to ANY valid JS function/method


await

await is always (and only) used inside of async functions/methods. We apply it to the actual asynchronous functionality and this makes your application treat that as a synchronous (or blocking) procedure. This means that we're going to pause any other operations and wait for the result from that procedure before moving on to any other code. That means instead of dealing with callbacks or then() methods, we can just assign that value to a variable and use it more explicitly.

async function getUsers() {
  const users = await User.find()
  return users
}

const getPosts = async () => {
  const posts = await Post.find()
  return posts
}

This syntax makes our code so much more readable.


Conclusion

In conclusion, if you're going to be dealing with asynchronous requests (and you will be), there is no better, more readable way to deal with these requests than getting comfortable with the async and await keywords to more efficiently deal with your Promises.