Javascript:其他异步函数中的异步嵌套函数会产生意外结果

时间:2013-04-13 00:39:48

标签: javascript ajax asynchronous nested

我有两个异步函数,一个嵌套在另一个中,如下所示:

  //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“活着”吗?

3 个答案:

答案 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的值可以变化,你捕获内部函数内的当前值