JavaScript异步回调和范围

时间:2013-04-29 09:50:36

标签: javascript asynchronous callback scope

考虑以下示例:

var cb = function (t) {
    console.log('callback -->' + t);
};

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout(function(){
        cb(i);
    },1000);
}

Working example at jsfiddle

此代码段的输出为:

0
1
2
callback ---> 3
callback ---> 3
callback ---> 3

一切都按预期工作,for循环将3个回调调用放入事件循环中。在for循环结束时i == 3并且当回调被执行时,所有这些都打印3,因为它们包含到i的链接,即3。 如何改进这个片段,以便在回调执行时它使用传递给它的实际值。

输出应为:

callback ---> 1
callback ---> 2
callback ---> 3

提前致谢。

4 个答案:

答案 0 :(得分:18)

Create a closure以便setTimeout处理程序将引用闭包的局部变量(在本例中,我们也命名为i),而不是来自循环的i

for (var i = 0; i < 3; i++) {
    (function (i) {
        console.log(i);
        setTimeout(function () {
            cb(i);
        }, 1000);
    }(i));
}

答案 1 :(得分:5)

您可以尝试 .bind

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout(cb.bind(null, i),1000);
}

The demo.

处理此问题的传统方法是创建一个闭包:

for(var i = 0; i<3; i++) {
    console.log(i);
    setTimeout((function(i){return function(){cb(i)}}(i)),1000);
}

答案 2 :(得分:3)

一个经常出现的问题。 让我们尝试使用JS未来的一些功能。我的意思是。 它创建局部范围变量,您不需要使用闭包或其他技巧。 但现在它仅适用于FF(我正在使用20.0.1)

for(var i = 0; i<3; i++) {
    console.log(i);
    let a = i;
    setTimeout(function(){               
        cb(a);
    },1000);
}

答案 3 :(得分:1)

我将在您的cb的functoin

中使用setTimeout()
var cb = function (t) {
  setTimeout(function(){
    console.log('callback -->' + t);
  },1000);
};


for(var i = 0; i<3; i++) {
    console.log(i);
        cb(i);
}