async/await 遇上 foreach导致的问题?

今天看到mdn上关于数组的foreach方法,有这样一段示例

let ratings = [5, 4, 5];

let sum = 0;

let sumFunction = async function (a, b) {
    return a + b;
} 

ratings.forEach(async function(rating) {
    sum = await sumFunction(sum, rating);
})

console.log(sum);
// Expected output: 14
// Actual output: 0

mdn说导致这种结果的原因和执行顺序有关,我想了很久也不能理解 就自己试着log了一些,以下是我的截图,我觉得执行顺序并没问题啊,为什么sum每次都是0呢,为什么没有串行而是并行执行了呢?
WechatIMG13364.jpeg

阅读 3.7k
5 个回答

打上 tag、再换组不同的数,可能更容易理解一下执行顺序:

image.png

可能你被 async / await 迷惑住了,以为每次 forEach 循环是串行的。实际它就是个语法糖而已,只是在 Function 内阻塞等待 Promise 执行完,但并不意味着会阻塞整个 forEach 的 callback。如果去掉这个语法糖,它实际等效于:

image.png

而你理解的所谓“串行”,实际应该写成:

image.png

可以去了解一下event looppromiseasync/await其实是promise的改进,其函数返回的也是一个promise对象。
上面不是并行执行,而是先执行完宏任务,再去执行微队列。你可以理解为sum = await sumFunction(sum,rating)一直都没有执行,而是压到一个栈里等待宏任务执行完,在执行完console.log(sum)后才开始执行微任务出栈赋值操作,最后微队列执行相当于

sum = sumFunction(0,5);
sum = sumFunction(0,4);
sum = sumFunction(0,5);

执行完在控制台中打印sum的值,你可以看到它是等于5
image.png

其实就是await导致sumFunction的调用变成了微任务,微任务追加到当前执行任务最后,这里即在console.log(sum)后执行。

async 函数会在第一个 await 处立即返回(返回一个 Promise )。

所以,所以在 forEach 运行结束的时候,直到最后的 console.log ,回调里的赋值一个都还没有发生。

好好理解even loop,其实就是同步和异步的先后顺序,异步又分优先级执行,也就是宏任务和微任务,先执行微任务再执行宏任务,promise是微任务,还有一些微任务等

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题