我有两个异步函数,一个嵌套在另一个中,如下所示:
//Async 1
document.addEventListener("click", function(event){
for (var i in event){
//Async 2
setTimeout(function(){
console.log(i);
}, 200*i);
}
});
我想要的是能够打印i
对象的每个条目(event
)。然而,Firefox上的输出是:
MOZ_SOURCE_KEYBOARD
MOZ_SOURCE_KEYBOARD
MOZ_SOURCE_KEYBOARD
MOZ_SOURCE_KEYBOARD
..
如果我将console.log(i)
移到 Async 2 之外,那么我会得到正确的结果:
type
target
currentTarget
eventPhase
bubbles
cancelable
..
为什么在阅读 async 2 内的i
时它无法正常工作?整个 Async 2 代码块中不应该event
“活着”吗?
答案 0 :(得分:1)
使用此:
document.addEventListener("click", function(event){
var count = 1;
for (var i in event){
//Async 2
setTimeout((function(i){
return function () {
console.log(i);
};
})(i), 200 * count++);
}
});
DEMO: http://jsfiddle.net/AQykp/
由于200*i
是一个字符串(甚至不是数字),因此i
我不确定你的目的是什么。但是我在答案中尝试用counter
修复它,假设你真正想要的是什么。
因此,您看到结果的原因是因为常见的闭包问题。在setTimeout
循环完成后,for
回调将执行,i
作为event
中的最后一个密钥。为了克服这个问题,你必须添加一个闭包来捕获循环中该点的i
值。
答案 1 :(得分:1)
setTimeout使用as出现在async1中。也就是说,它在创建超时函数时引用i而不是使用i的值。当你的超时函数最终运行时,它会查看i的当前值,这是for循环后event
中的最后一个键。
您可以通过使用自调用函数来避免这种情况,这样该函数的参数对于超时函数是本地的:
for (var i in event) {
setTimeout((function(i) {
return function() { console.log(i); }
})(i), 200 * i);
}
答案 2 :(得分:0)
在你的回调中,事件确实存在。 问题在于,当你的函数执行时,i的值已经改变了(从我从输出中可以看到,循环已经结束并且我已经达到它的最大值)并因此为每个回调输出相同的值
如果您使用Ian评论的功能,您将把实际值计入新功能。这样,i的值可以变化,你捕获内部函数内的当前值