ES6 变量作用域位于循环中,内部有await

Ngu*_*ong 3 javascript asynchronous promise ecmascript-6

我们可能知道,var关键字在全局范围内定义一个变量,或者在整个函数中局部定义一个变量,而不管块作用域如何。因此,下面的代码将记录5具有相同值的时间。

for(var i = 0; i < 5; i++){
  setTimeout(() => console.log(i), 2000);
}
Run Code Online (Sandbox Code Playgroud)

像这样可视化上面的 JS 运行时 在此输入图像描述 正如你所看到的,Callback Queue中的 5 个任务将等待Call stack为空。因此,在同步循环完成后 - 这意味着在我的情况下调用堆栈为空,然后将执行5 个计划任务 -console.log(i)其值i等于。你可以在这里5

我想要的是在之后立即登录i == 2。它按我的预期工作。

for(var i = 0; i < 5; i++){
  setTimeout(() => console.log(i), 2000);
}
Run Code Online (Sandbox Code Playgroud)

但我很好奇它是如何工作的,而我不确定调用堆栈是否为空?当我使用 时await,是否允许异步函数的调用者恢复执行,或者其他什么?

图像流的任何解释/可视化将不胜感激。谢谢。

JLR*_*she 5

await放弃对线程的控制并允许其他进程运行,直到等待的承诺得到解决。即使承诺已经解决await也会产生任何一直在等待执行的“微任务”,但这在您的情况下是一个没有意义的问题,因为您的承诺需要整整两秒钟才能解决。

在您的情况下,两个setTimeouts 在 之前排队await,因此在发生这种情况时允许它们运行await

时间线基本上是这样的:

  • 我=0
  • setTimeout 1 已安排
  • 我 = 1
  • setTimeout 2 已安排
  • 我 = 2
  • 等待
  • setTimeout 1 回调运行
  • setTimeout 2 回调运行
  • setTimeout 3 已安排
  • 我 = 3
  • setTimeout 4 已安排
  • 我 = 4
  • setTimeout 5 已安排
  • 我 = 5
  • 循环结束
  • setTimeout 3 回调运行
  • setTimeout 4 回调运行
  • setTimeout 5 回调运行

可以看到,i当第一对setTimeouts被允许执行时,它是2,而当剩下的3对s执行时,它是5。

这是一个片段,希望能更好地演示该过程:

var sleep = (ms) => new Promise(resolve => setTimeout(() => resolve(1), ms));
async function runAsync() {
  for (var i = 0; i < 5; i++) {
    console.log('i is now', i);
    if (i == 2) {
      console.log('about to sleep');
      await sleep(5000);
      console.log('now done sleeping');
    }
    console.log('about to setTimeout. i is', i, 'right now');
    setTimeout(() => {
        console.log('setTimeout task running:', i, '- scheduling a new timeout.');
        setTimeout(() => console.log('inner timeout:', i), 1000);
    });
  }
  console.log('done looping. i is', i);
}

runAsync();
Run Code Online (Sandbox Code Playgroud)