async/await issues you might overlook

one example

Here is a common vue code snippet:

 async initStore(query) {
    await this.getConfig();
    await this.getUser();
    await this.checkRussianContext(query);

    await this.getBasket(this.$store.state.config.selectedCurrency),

    await this.$store.dispatch('options/fetchOptions', {
      basket : this.$store.state.basket,
    });
 },

In the above code, each line will wait for the result of the previous line to return before executing. For example, getUser will wait for the getConfig data to return before executing.

The following things should come to mind when looking at this code:

  • What if the execution of a row does not require the data from the row above? Why does blocking code slow down the entire application?
  • Can we make all unrelated methods execute together? Like using Promise.all?
  • Can the related methods be chained using then to avoid blocking the rest of the code?

The focus of this article is to help you find bad code smells by analyzing the problems that async/await may cause.

 

Please execute unrelated requests in parallel

Let's look at some concrete data.

Here is sample code:

const getUserData = async () => {
  // Get a random dog picture as avatar
  const res = await fetch('https://dog.ceo/api/breeds/image/random')
  const { message } = await res.json()

  // Get randomly generated user information
  const user = await fetch('https://randomuser.me/api/')
  const { results } = await user.json()

  // ...
}

The above code is executed 100 times under fast 3G (using Chrome developer tools), the average execution time is 1231.10ms

But obviously, the second request does not need the result of the first request, so we modify it to the following code and execute it 100 times:

const getUserDataFaster = async () => {
  // Two requests are executed in parallel
  const [res, user] = await Promise.all([
    fetch('https://dog.ceo/api/breeds/image/random'), 
    fetch('https://randomuser.me/api/')
  ])
  const [{ message }, { results }] = await Promise.all([res.json(), user.json()])

  // ...
}

We got an average execution time of 612.50ms, which is almost half the time.

The key point: parallel execution of query requests as much as possible.

You can use the code experience in this codepen

Guangzhou Design Companyhttps://www.houdianzi.com My 007 office resource websitehttps://www.wode007.com

irrelevant code you don't have to wait

Another example:

async initStore(query) {
   await Promise.all([
     this.getConfig(),
     this.getUser(),
     this.checkRussianContext(query)
   ])

   await this.getBasket(this.$store.state.config.selectedCurrency),

   await this.$store.dispatch('options/fetchOptions', {
     basket : this.$store.state.basket,
   });

   await initBooking()
},

The first 3 requests are executed in parallel, and the next piece of code relies on the data obtained earlier, so it needs to be executed after that, but have you found any problems?

The poor initBooking can only be executed after getBasket and fetchOptions are completed, although it does not need any data from these two methods.

A simple solution is to replace await with .then to use:

For this usage, see another article at the beginning
async initStore(query) {
  await Promise.all([
    this.getConfig(),
    this.getUser(),
    this.checkRussianContext(query)
  ])

  this.getBasket(this.$store.state.config.selectedCurrency).then(async () => {
    await this.$store.dispatch('options/fetchOptions', {
      basket : this.$store.state.basket,
    });
  })   

  await initBooking()
},

In this way, both getBasket and initBooking can be executed in parallel.

Tags: Javascript

Posted by oc1000 on Wed, 11 May 2022 03:30:18 +0300