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

阅读 525
评论
    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

        • 7.5k

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

          • 9.3k

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

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

            • 2
            • 新人请关照

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

              撰写回答

              登录后参与交流、获取后续更新提醒