为什么让异步循环工作而var不工作呢?

时间:2019-07-24 18:48:29

标签: javascript node.js

我很难理解为什么let在JavaScript中的异步循环中起作用。

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

我的代码看起来像这样:

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

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

}

该数组从最大i值而不是row[i]中的0开始。我了解自己做错了什么,但是当我寻找解决方案时,发现使用let而非var i可以解决此问题。

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

2 个答案:

答案 0 :(得分:0)

var具有功能范围。

let具有阻止范围。

因此,在这样的for循环中:

for (let i = 0; i < row.length; i++) 

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

由于var是函数范围的,因此在执行此操作时:

for (var i = 0; i < row.length; i++) 

整个函数中只有一个i变量,并且for循环的每个迭代都使用相同的变量。 for循环的第二次迭代更改了i的值,第一次迭代中的任何异步操作都可能尝试使用该值。如果这些异步操作试图在异步回调中使用其i的值,则可能导致问题,因为与此同时for循环将对其进行更改。

这是一个经典的例子:

for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 10);
}

而且,现在有了let

for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);
    }, 10);
}

运行每个并查看结果差异。在两个示例中,for循环运行完成并调度5个计时器。在var示例中,所有计时器回调都从现已完成的i循环中看到一个for变量,因此它们都将5输出为{{1}的值}。

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

答案 1 :(得分:-1)

我要看的一件事是for循环的每个迭代是否正在等待异步函数解析。在您连接到数据库并执行操作之前,它可能一直持续运行。这就是为什么它从max开始的原因。

除此之外,尚不清楚即使在here.中显示了新的块范围规则的情况下,为什么仍要使用'let'还是很重要