为什么 let 可以在异步 for 循环中工作,而 var 却不能?

jed*_*edu -1 javascript node.js

我很难理解为什么letJavaScript 中的 async for 循环可以工作。

我正在使用异步函数从数据库中执行各种插入和检索

我的代码看起来像这样:

for (var i = 0; i < row.length; i++) {
   pool.query(`Select Name from Students where ID = ${row[i].PartID}`)

                .then(rows => {
                    ....
                    ....

}
Run Code Online (Sandbox Code Playgroud)

数组是从最大值开始的,i而不是row[i]. 我明白我做错了什么,但是当我寻找解决方案时,我发现使用let而不是var i解决问题。

然而我不明白为什么会这样。为什么 using 会在异步函数执行之前let阻止变量增加?i

jfr*_*d00 6

var有功能范围。

let具有块作用域。

所以,在for这样的循环中:

for (let i = 0; i < row.length; i++) 
Run Code Online (Sandbox Code Playgroud)

循环的每次迭代都有其自己的单独i变量。当在循环内使用异步操作时,每个单独的i变量都具有自己的异步回调,因此一个变量不会覆盖另一个变量。

由于var是函数作用域,因此当您执行以下操作时:

for (var i = 0; i < row.length; i++) 
Run Code Online (Sandbox Code Playgroud)

i整个函数中只有一个变量,并且for循环的每次迭代都使用相同的变量。循环的第二次迭代更改了第一次迭代中的任何异步操作可能尝试使用for的值。i如果这些异步操作尝试i在异步回调中使用它们的值,这可能会导致问题,因为同时for循环已经更改了它。

这是一个经典的例子:

for (let i = 0; i < row.length; i++) 
Run Code Online (Sandbox Code Playgroud)

并且,现在与let

for (var i = 0; i < row.length; i++) 
Run Code Online (Sandbox Code Playgroud)

运行每一个并查看结果的差异。在这两个示例中,for循环运行直至完成并调度 5 个计时器。在该示例中,所有计时器回调都看到来自现已完成的循环的var一个变量,因此它们都输出为 的值。ifor5i

let示例中,循环的每次迭代都有自己的i变量,该变量不受循环进行的影响for,因此当调用计时器回调时(for循环完成后),它们仍然具有i与迭代时相同的值循环的for最初被执行,因此它们输出预期的递增数字序列。