在我的观点中,我在一本书中遇到了奇怪的断言。我想我不明白,但无论如何,如果你了解情况会很好。
ajax('<host1>/items',
items => {
for (let item of items) {
ajax(`<host2>/items/${item.getId()}/info`,
dataInfo => {
ajax(`<host3>/files/${dataInfo.files}`,
processFiles);
});
}
});
作者注意:
此代码还有另一个隐藏的问题。你能猜出这是什么?当您混合一个同步工件(如for..of命令块)调用异步函数时,就会发生这种情况。循环并不知道这些调用存在延迟,因此无论如何它们总是会前进,这可能会导致一些真正无法预测且难以诊断的错误。在这些情况下,您可以通过使用forEach()而不是循环来管理异步函数的闭包来改善问题。
而不是它们提供以下内容:
ajax('/data',
items => {
items.forEach(item => {
// process each item
});
});
坦率地说,我希望如果我们使用let
for循环,这意味着我们为每次迭代创建一个闭包,因此我没有看到任何隐藏的问题。
答案 0 :(得分:2)
你是对的,如果作者的评论是在那个确切的代码片段上,那就错了。
循环不知道这些调用有延迟[...]你可以通过使用forEach()来改善问题
没有任何改变,forEach()
同样不知道在其回调中进行的异步调用,因为for循环是在其体内进行的异步调用。 forEach()
将始终向前迈进#34;与for循环相同的方式。
使用let
,您无法遇到作者似乎担心的问题,因为循环的每次迭代都有自己的item
,就像使用items.forEach( item => { ...
时一样。
即使使用var
,该代码也没有问题,因为变量item
未在ajax请求的回调中使用。您可以使用var
并在回调中使用item
来产生作者的关注,例如:console.log( item.getId() );
。
注意:重要的是要注意回调最有可能以不同的(看似随机的)顺序运行。如果你不知道它会导致令人惊讶的错误,但是也与使用循环与forEach无关。
答案 1 :(得分:1)
这本书的作者似乎毫无头绪。 for (let … of …)
可以修复.forEach(…)
没有问题。
他们谈论
围绕异步函数创建闭包,使用forEach()而不是循环
进行管理
但闭包不是由forEach
回调函数创建的,闭包是传递给ajax
函数的回调。它关闭在周围的范围内,for
块范围(使用let
或const
时)与函数体范围之间几乎没有任何区别(使用forEach
时。