In 6 reasons Async/Await should replace Promise, we compare two different asynchronous programming methods: Async/Await and Promise. This blog will show how Async/Await simplifies JavaScript code with sample code.

  • 译 文: ASYNC/AWAIT WILL MAKE YOUR CODE SIMPLER
  • Translator: Fundebug

To ensure readability, free translation rather than literal translation is used in this paper. In addition, the copyright of this article belongs to the original author, and translation is for study only.

Async/Await is a new ES7 feature of JavaScript, derived from. NET and c #. It is possible to write asynchronous code without using callback functions, like synchronous code. This blog post will use code examples to show how Async/Await can simplify JavaScript code.

1. Remove the callback function

No additional libraries are required to run the sample code in this article. The latest versions of mainstream browsers such as Chrome, Firefox, Safari and Edge all support Async/Await syntax. Node.js 7.6+ also supports Async/Await syntax.

We wrote some simple APIS to simulate asynchronous operations. These interfaces all return promises and resolve some data after 200ms.

class Api {
  constructor () {
    this.user = { id: 1, name: 'test' }
    this.friends = [ this.user, this.user, this.user ]
    this.photo = 'not a real photo'
  }
  getUser () {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(this.user), 200)
    })
  }
  getFriends (userId) {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(this.friends.slice()), 200)
    })
  }
  getPhoto (userId) {
    return new Promise((resolve, reject) => {
      setTimeout(() => resolve(this.photo), 200)
    })
  }
  throwError () {
    return new Promise((resolve, reject) => {
      setTimeout(() => reject(new Error('Intentional Error')), 200)
    })
  }
}Copy the code

Nested Promise

function callbackHell () {
  const api = new Api()
  let user, friends
  api.getUser().then(function (returnedUser) {
    user = returnedUser
    api.getFriends(user.id).then(function (returnedFriends) {
      friends = returnedFriends
      api.getPhoto(user.id).then(function (photo) {
        console.log('callbackHell', { user, friends, photo })
      })
    })
  })
}Copy the code

Developers who have used Promise to write callback functions will be familiar with the fact that layers of nested code often end like this:

})})})}Copy the code

Calling callback functions within callback functions, nested layer by layer, is called “callback hell.” In real code, such cases are not uncommon and are often more complex.

Chain Promise

function promiseChain () {
  const api = new Api()
  let user, friends
  api.getUser()
    .then((returnedUser) => {
      user = returnedUser
      return api.getFriends(user.id)
    })
    .then((returnedFriends) => {
      friends = returnedFriends
      return api.getPhoto(user.id)
    })
    .then((photo) => {
      console.log('promiseChain', { user, friends, photo })
    })
}Copy the code

One of the best features of promises is that you can return a new Promise in the then callback, which allows you to link these promises together with only one layer of nesting. Chained promises are much simpler than nested promises, but they still have a lot of redundancy.

Async/Await

Is it ok not to use the callback function? Of course you can! 7 lines of code with Async/Await.

async function asyncAwaitIsYourNewBestFriend () { const api = new Api() const user = await api.getUser() const friends =  await api.getFriends(user.id) const photo = await api.getPhoto(user.id) console.log('asyncAwaitIsYourNewBestFriend', { user, friends, photo }) }Copy the code

With the await keyword, the assignment will wait until the end of the asynchronous operation. In this way, it looks like synchronous code, but execution is actually asynchronous.

2. Simplify the loop

Async/Await can make complex operations such as loops easy. For example, what if we need to get a list of all the friends of a user?

The use of Promise

function promiseLoops () {  
  const api = new Api()
  api.getUser()
    .then((user) => {
      return api.getFriends(user.id)
    })
    .then((returnedFriends) => {
      const getFriendsOfFriends = (friends) => {
        if (friends.length > 0) {
          let friend = friends.pop()
          return api.getFriends(friend.id)
            .then((moreFriends) => {
              console.log('promiseLoops', moreFriends)
              return getFriendsOfFriends(friends)
            })
        }
      }
      return getFriendsOfFriends(returnedFriends)
    })
}Copy the code

We use the recursive function getFriendsOfFriends to get friends-of-Friends, knowing that the Friends array is empty. This is obviously too complicated for such a simple task.

Using promise.all (), instead of a loop, it executes concurrently.

Use the Async/Await

This could be so much easier.

async function asyncAwaitLoops () {
  const api = new Api()
  const user = await api.getUser()
  const friends = await api.getFriends(user.id)
  for (let friend of friends) {
    let moreFriends = await api.getFriends(friend.id)
    console.log('asyncAwaitLoops', moreFriends)
  }
}Copy the code

In this case, you can use the for loop directly, which is very simple.

3. Simplify concurrency

Getting friends-of-friends one by one through a loop is too slow, and concurrency is easier.

async function asyncAwaitLoopsParallel () { const api = new Api() const user = await api.getUser() const friends = await  api.getFriends(user.id) const friendPromises = friends.map(friend => api.getFriends(friend.id)) const moreFriends = await Promise.all(friendPromises) console.log('asyncAwaitLoopsParallel', moreFriends) }Copy the code

To achieve concurrency, simply take the Promise array as an argument to promise.all (). Thus, you only need to await a Promise, which will resolve when all concurrent operations end.

4. Simplify error handling

Use the callback function to handle the Promise error

function callbackErrorHell () {
  const api = new Api()
  let user, friends
  api.getUser().then(function (returnedUser) {
    user = returnedUser
    api.getFriends(user.id).then(function (returnedFriends) {
      friends = returnedFriends
      api.throwError().then(function () {
        console.log('Error was not thrown')
        api.getPhoto(user.id).then(function (photo) {
          console.log('callbackErrorHell', { user, friends, photo })
        }, function (err) {
          console.error(err)
        })
      }, function (err) {
        console.error(err)
      })
    }, function (err) {
      console.error(err)
    })
  }, function (err) {
    console.error(err)
  })
}Copy the code

This is bad, and the code is redundant and unreadable.

Use the catch method to handle Promise errors

function callbackErrorPromiseChain () {
  const api = new Api()
  let user, friends
  api.getUser()
    .then((returnedUser) => {
      user = returnedUser
      return api.getFriends(user.id)
    })
    .then((returnedFriends) => {
      friends = returnedFriends
      return api.throwError()
    })
    .then(() => {
      console.log('Error was not thrown')
      return api.getPhoto(user.id)
    })
    .then((photo) => {
      console.log('callbackErrorPromiseChain', { user, friends, photo })
    })
    .catch((err) => {
      console.error(err)
    })
}Copy the code

This is much better, just use the catch method at the end of the Promise chain to handle all errors.

Handle Async/Await errors with Try/Catch

async function aysncAwaitTryCatch () {
  try {
    const api = new Api()
    const user = await api.getUser()
    const friends = await api.getFriends(user.id)
    await api.throwError()
    console.log('Error was not thrown')
    const photo = await api.getPhoto(user.id)
    console.log('async/await', { user, friends, photo })
  } catch (err) {
    console.error(err)
  }
}Copy the code

For Async/Await code, use Try/Catch to handle it, just like synchronous code, much simpler.

Whenever you need to monitor your JavaScript code for errors online, you can use Fundebug’s real-time error monitoring service for free, with just one line of code!

5. Simplify your code organization

Functions defined using the async keyword return promises, making it easier to organize code.

For example, in the previous example, we could return the retrieved user information instead of printing it directly; We can then retrieve the user information through the returned Promise.

async function getUserInfo () {
  const api = new Api()
  const user = await api.getUser()
  const friends = await api.getFriends(user.id)
  const photo = await api.getPhoto(user.id)
  return { user, friends, photo }
}
function promiseUserInfo () {
  getUserInfo().then(({ user, friends, photo }) => {
    console.log('promiseUserInfo', { user, friends, photo })
  })
}Copy the code

Using Async/Await syntax, it is even simpler:

async function awaitUserInfo () {
  const { user, friends, photo } = await getUserInfo()
  console.log('awaitUserInfo', { user, friends, photo })
}Copy the code

How do I get information about multiple users?

async function getLotsOfUserData () {
  const users = []
  while (users.length < 10) {
    users.push(await getUserInfo())
  }
  console.log('getLotsOfUserData', users)
}Copy the code

How to concurrency? How do you handle errors?

async function getLotsOfUserDataFaster () { try { const userPromises = Array(10).fill(getUserInfo()) const users = await  Promise.all(userPromises) console.log('getLotsOfUserDataFaster', users) } catch (err) { console.error(err) } }Copy the code









Are your users experiencing bugs?

Experience the Demo
Free to use