将参数传递给setTimeout的闭包

时间:2012-06-01 18:23:16

标签: javascript jquery internet-explorer-9 closures document-ready

我遇到了一个问题,我的应用程序位于iframe中,而且它是从外部域调用的。当iframe正确加载时,IE9不会触发加载事件,因此我认为我使用setTimeout来调查页面。

无论如何,我想看看我的setTimeout通常需要多长时间才能完成,所以我希望能够记录setTimeout从我的回调中触发的延迟,但是我不知道如何传递该上下文进入它所以我可以记录它。

App.readyIE9 = function() {
  var timings = [1,250,500,750,1000,1500,2000,3000];    
  for(var i = 0; i < timings.length; i++) {
    var func = function() {
    if(App.ready_loaded) return;
      console.log(timings[i]);
      App.readyCallBack();
    };
    setTimeout(func,timings[i]);
  }
};

我一直在IE9的控制台中获取LOG:

实现这个目标的正确方法是什么?

由于

3 个答案:

答案 0 :(得分:10)

当你的函数在将来的某个时间被setTimeout调用时,i的值已经for循环增加到它的范围的末尾,所以{{1} }报告console.log(timings[i]);

要在该函数中使用undefined,您需要在函数闭包中捕获它。有几种方法可以做到这一点。我建议使用自执行函数来捕获i的值,如下所示:

i

作为对其工作原理的一点解释:App.readyIE9 = function() { var timings = [1,250,500,750,1000,1500,2000,3000]; for(var i = 0; i < timings.length; i++) { (function(index) { setTimeout(function() { if(App.ready_loaded) return; console.log(timings[index]); App.readyCallBack(); }, timings[index]); })(i); } }; 作为该函数的第一个参数传递给自执行函数。第一个参数名为i,并在每次调用自执行函数时被冻结,因此index循环不会导致它在执行for回调之前发生变化。因此,在自执行函数内部引用setTimeout将获得每个index回调的数组索引的正确值。

答案 1 :(得分:10)

这种情况正在发生,因为您没有在i中缩小func的价值。循环完成后,i为8(timings.length),这在数组中不存在。

你需要做这样的事情:

App.readyIE9 = function() {
  var timings = [1,250,500,750,1000,1500,2000,3000];    
  for(var i = 0; i < timings.length; i++) {
    var func = function(x) {
      return function(){
          if(App.ready_loaded) return;
          console.log(timings[x]);
          App.readyCallBack();
      };
    };
    setTimeout(func(i),timings[i]);
  }
};

答案 2 :(得分:3)

使用setTimeoutsetInterval回调时,这是一个常见问题。您应该将i值传递给函数:

var timings = [1, 250, 500, 750, 1000, 1500, 2000, 3000],
    func = function(i) {
        return function() {
            console.log(timings[i]);
        };
    };

for (var i = 0, len = timings.length; i < len; i++) {
    setTimeout(func(i), timings[i]);
}

DEMO: http://jsfiddle.net/r56wu8es/