以我的观点,我在一本书中遇到了奇怪的断言。我想我有些不明白,但无论如何,如果您能说明情况,那就太好了。
ajax('<host1>/items',
items => {
for (let item of items) {
ajax(`<host2>/items/${item.getId()}/info`,
dataInfo => {
ajax(`<host3>/files/${dataInfo.files}`,
processFiles);
});
}
});
作者关注:
There’s another hidden problem with this code. Can you guess what it is? It occurs when you mix a synchronous artifact like a for..of imperative block invoking asynchronous functions. Loops aren’t aware that there’s latency in those calls, so they’ll always march ahead no matter what, which can cause some really unpredictable and hard-to-diagnose bugs. In these situations, you can improve matters by creating closures around your asynchronous functions, managed by using forEach() instead of the loop.
取而代之的是,他们提供了以下内容:
ajax('/data',
items => {
items.forEach(item => {
// process each item
});
});
坦率地说,我希望如果我们使用 let
for 循环,这意味着我们为每次迭代创建一个闭包,因此我看不到任何隐藏的问题。
最佳答案
你是对的,如果作者的评论是针对那个确切的代码片段,那他们就错了。
Loops aren’t aware that there’s latency in those calls [...] you can improve matters by [...] using forEach()
这没有任何改变,forEach()
同样不知道其回调内部进行的异步调用,因为 for 循环是在其主体中进行的异步调用。 forEach()
将“始终向前推进”,就像 for 循环一样。
使用 let
就不会遇到作者担心的问题,因为循环的每次迭代都有自己的 item
就像使用 一样items.forEach( item => { ...
.
即使使用 var
,该代码也没有问题,因为变量 item
没有在 ajax 请求的回调中使用。您可以通过在回调中使用 var
和使用 item
来产生作者的关注,例如:console.log( item.getId() );
.
注意:重要的是要注意回调很可能会以与它们启动时不同的顺序(看似随机的)运行。如果您不知道它可能会导致令人惊讶的错误,但它也有与使用循环还是使用 forEach 无关。
关于javascript - 关于通过 let 声明变量的变量范围的疑问,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48174506/