这个问题在这里已经有答案了:
循环内的javascript闭包-简单实用示例(44个答案)
两年前关门了。
我正在运行以下形式的事件循环:
var i;
var j = 10;
for (i = 0; i < j; i++) {
asynchronousProcess(callbackFunction() {
alert(i);
});
}
我正在尝试显示一系列显示数字0到10的警报。问题是,当回调函数被触发时,循环已经经历了一些迭代,并且它显示了一个更高的值 i
. 关于如何解决这个问题有什么建议吗?
6条答案
按热度按时间gmxoilav1#
javascript代码在单个线程上运行,因此您不能在开始下一个循环迭代之前等待第一个循环迭代完成,而不会严重影响页面可用性。
解决办法取决于你真正需要什么。如果这个例子接近你所需要的,@simon建议通过
i
异步进程是一个很好的方法。ix0qys7i2#
async await
在这里(es7),所以你现在可以很容易地做这类事情。记住,只有在
asycronouseProcess
正在返回一个Promise
如果asycronouseProcess
如果不在你的控制范围内,那么你可以让它返回一个Promise
像这样一个人然后更换此线路
await asycronouseProcess();
由await asyncProcess();
理解Promises
在调查之前async await
是必须的(同时阅读关于支持async await
)cfh9epnr3#
es2017:您可以将异步代码 Package 到返回承诺(承诺中的异步代码)的函数(比如xhrpost)中。
然后调用for循环中的函数(xhrpost),但使用神奇的await关键字。:)
368yc8dk4#
这个
for
当所有异步操作启动时,循环立即运行到完成。当它们在将来某个时间完成并调用回调时,循环索引变量的值i
对于所有回调都将是其最后一个值。这是因为
for
循环不会等到异步操作完成后再继续循环的下一次迭代,因为异步回调将在将来某个时候调用。因此,循环完成其迭代,然后在异步操作完成时调用回调。因此,循环索引是“done”的,并且对于所有回调都位于其最终值。为了解决这个问题,您必须为每个回调单独保存循环索引。在javascript中,这样做的方法是在函数闭包中捕获它。这可以通过专门为此目的创建一个内联函数闭包来实现(下面显示的第一个示例),也可以创建一个将索引传递给的外部函数,并让它为您唯一地维护索引(下面显示的第二个示例)。
从2016年起,如果您有一个完全符合规范的javascript es6实现,您还可以使用
let
定义for
循环变量,它将为for
循环(下面的第三个实现)。但是,请注意,这是es6实现中的一个后期实现特性,因此您必须确保您的执行环境支持该选项。使用.foreach()进行迭代,因为它创建了自己的函数闭包
使用iife创建自己的函数闭包
创建或修改外部函数并将变量传递给它
如果你能修改
asynchronousProcess()
函数,然后您可以在其中传递值asynchronousProcess()
将cntr函数返回回调,如下所示:使用es6
let
如果您有一个完全支持es6的javascript执行环境,那么可以使用let
在你的for
循环如下:async function someFunction() {
const j = 10;
for (let i = 0; i < j; i++) {
// wait for the promise to resolve before advancing the for loop
await asynchronousProcess();
console.log(i);
}
}
function someFunction() {
let promises = [];
for (let i = 0; i < 10; i++) {
promises.push(asynchonousProcessThatReturnsPromise());
}
return Promise.all(promises);
}
someFunction().then(results => {
// array of results in order here
console.log(results);
}).catch(err => {
console.log(err);
});
cs7cruho5#
关于如何解决这个问题有什么建议吗?
好几个。您可以使用绑定:
或者,如果您的浏览器支持let(它将出现在下一个ecmascript版本中,但是firefox已经支持了一段时间),您可以:
或者,你可以做
bind
手动(如果浏览器不支持它,但我想说您可以实现一个垫片,在这种情况下,它应该在上面的链接中):我通常更喜欢
let
当我可以使用它时(例如firefox插件);否则bind
或者自定义currying函数(不需要上下文对象)。pw9qyyiw6#
下面是一个示例函数方法,用于实现这里所期望的功能。