简体   繁体   中英

Strange behavior inside async function

I'm learning Promises and I tried to fetch some data inside an async function.

Here's the snippet -

 import "./styles.css"; import axios from "axios"; let jsonPlaceholder = axios.create({ baseURL: "https://jsonplaceholder.typicode.com/" }) let fetchData = async () => { console.log("INSIDE FETCH DATA FUNCTION") let response = await jsonPlaceholder.get('/users'); return response.data; } let runSetTimeoutTenTimes = () => { for(let i=0; i<10; i++) { setTimeout(async () => { let data = await fetchData(); console.log("HERE IS THE USER DATA....",data); }) } } runSetTimeoutTenTimes();

I was expecting the output similar to the below format in console:

INSIDE FETCH DATA FUNCTION
HERE'S THE DATA....
(10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]

INSIDE FETCH DATA FUNCTION
HERE'S THE DATA....
(10) [Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
.
.
.

However I am getting data in the below format:

截屏

It looks like fetchData is run 10 times and then fetched data are logged one by one.

Here is the Codesandbox link

What am I missing here?

EDIT:

If I replace the fetchData and runSetTimeoutTenTimes with the below functions I am getting the desired result:

let fetchData_1 = async () => {
  console.log("INSIDE FETCH DATA FUNCTION")
  return;
}

let runSetTimeoutTenTimes = () => {
  for(let i=0; i<10; i++) {
    setTimeout(async () => {
       await fetchData();          
       console.log("HERE IS THE USER DATA....");
    })
  }
} 

Realise that what occurs before the await inside fetchData will execute immediately, while the part that follows it will run later, asynchronously.

As your timers expired quite quickly, the 10 calls to fetchData are made quite quickly one after the other, ... before any of the awaited get promises are resolved, and so the synchronous part of fetchData is executed 10 times before any of the return statements in fetchData are executed, since those can only execute when the get promises resolve.

So that explains why you first get a bunch of "INSIDE FETCH DATA FUNCTION" messages and only then get a series of "HERE IS THE USER DATA....".

If you want to serialise this completely, then the easiest is to promisify setTimeout as follows:

import "./styles.css";
import axios from "axios";

let jsonPlaceholder = axios.create({
  baseURL : "https://jsonplaceholder.typicode.com/"
})

let fetchData = async () => {
  console.log("INSIDE FETCH DATA FUNCTION")
  let response = await jsonPlaceholder.get('/users');
  return response.data;
}

// promisified setTimeout:
let delay = ms => new Promise(resolve => setTimeout(resolve, ms));

let runSetTimeoutTenTimes = async () => { // <-- make async
  for(let i=0; i<10; i++) {
    // Here comes the timeout, only when it expires can we proceed below:
    await delay(100);
    let data = await fetchData();          
    console.log("HERE IS THE USER DATA....",data);
  }
}

runSetTimeoutTenTimes();

Of course, this time out is not necessary, so you can leave out await delay(100) completely. Then you have a situation where the next get request is made once the previous one is resolved.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM