async/await函数的执行顺序的理解

最近遇到一个关于async函数使用的Bug,因代码涉及太多业务,所以模拟了代码, 如下:

let testArr = [1, 2, 3]
let flag = false

const func = (res) => {
  return new Promise((resolve, reject) => {
    if (res) {
      resolve(res)
    }
  })
}

testArr.forEach(async (item) => {
  await func(item).then(res => {
    flag = true
    console.log('res', res, flag)
  })
})

console.log('flag', flag)

当时写代码的人的目的很简单,就是要让异步函数变成同步来执行,按如下输出:

res 1 true
res 2 true
res 3 true
flag true

但实际输出的是:

flag false
res 1 true
res 2 true
res 3 true

当时我也觉得奇怪的,为什么await没有生效?真的没有生效?

于是我在await 后面加了一个console.log(‘inside’, flag), 代码如下

let testArr = [1, 2, 3]
let flag = false

const func = (res) => {
  return new Promise((resolve, reject) => {
    if (res) {
      resolve(res)
    }
  })
}

testArr.map(async (item) => {
  await func(item).then(res => {
    flag = true
    console.log('res', res, flag)
  })
  console.log('inside', flag)
})

console.log('flag', flag)

输出如下

flag false
res 1 true
res 2 true
res 3 true
inside true
inside true
inside true

也就是说,其实在函数里面await是生效了?那为是什么外面就没有生效?

很多人以为await会一直等待之后的表达式执行完之后才会继续执行后面的代码,实际上await是一个让出线程的标志

await后面的函数会先执行一遍,然后就会跳出整个async函数来执行后面js栈的代码。

等本轮事件循环执行完了之后又会跳回到async函数中等待await后面表达式的返回值。

如果返回值为非promise,则继续执行async函数后面的代码,

否则将返回的promise,放入promise队列(Promise的Job Queue), 然后等待promise任务队列执行完之后,再执行await后面的代码

所以,如果要让flag变成true,需要再用一个async函数,修改的代码如下:

let testArr = [1, 2, 3]
let flag = false

const func = (res) => {
  return new Promise((resolve, reject) => {
    if (res) {
      resolve(res)
    }
  })
}
async function container () {
  await testArr.map(async (item) => {
    await func(item).then(res => {
      flag = true
      console.log('res', res, flag)
    })
    console.log('inside', flag)
  })
  console.log('flag', flag)
}
container()

输出:

res 1 true
res 2 true
res 3 true
flag true
inside true
inside true
inside true

从其他博主看到这样一段代码,我觉得非常经典:

function testSometing() {
  console.log("执行testSometing");
  return "testSometing";
}

async function testAsync() {
  console.log("执行testAsync");
  return Promise.resolve("hello async");
}

async function test() {
  console.log("test start...");
  const v1 = await testSometing();//关键点1
  console.log(v1);
  const v2 = await testAsync();
  console.log(v2);

  console.log(v1, v2);
}

test();

var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//关键点2
promise.then((val)=> console.log(val));

console.log("test end...")

输出:

test start...
执行testSometing
promise start..
test end...
testSometing
执行testAsync
promise //第七位
hello async
testSometing hello async

调整了一下代码顺序

function testSometing() {
  console.log("执行testSometing");
  return "testSometing";
}

async function testAsync() {
  console.log("执行testAsync");
  return Promise.resolve("hello async");
}

async function test() {
  console.log("test start...");
  const v2 = await testAsync();
  console.log(v2);
  const v1 = await testSometing();//关键点1
  console.log(v1);

  console.log(v1, v2);
}

test();

var promise = new Promise((resolve)=> { console.log("promise start.."); resolve("promise");});//关键点2
promise.then((val)=> console.log(val));

console.log("test end...")

输出:

test start...
执行testAsync
promise start..
test end...
promise    //第五位
hello async
执行testSometing
testSometing
testSometing hello async

区别主要是’promise’的出现的位置,所以:

如果返回值为非promise,则继续执行async函数后面的代码,哪怕外面已经有任务队列在排队

否则将返回的promise,放入promise队列(Promise的Job Queue), 然后等待promise任务队列执行完之后,再执行await后面的代码

猜你喜欢

转载自blog.csdn.net/guzhao593/article/details/84191401