javascript for循环中的异步进程

javascript for循环中的异步进程,javascript,asynchronous,for-loop,synchronization,Javascript,Asynchronous,For Loop,Synchronization,我正在运行以下形式的事件循环: var i; var j = 10; for (i = 0; i < j; i++) { asynchronousProcess(callbackFunction() { alert(i); }); } vari; var j=10; 对于(i=0;i

我正在运行以下形式的事件循环:

var i;
var j = 10;
for (i = 0; i < j; i++) {

    asynchronousProcess(callbackFunction() {
        alert(i);
    });
}
vari;
var j=10;
对于(i=0;i

我试图显示一系列显示数字0到10的警报。问题是,在触发回调函数时,循环已经经过了几次迭代,并且它显示了更高的值
i
。关于如何修复此问题的任何建议?

JavaScript代码在单个线程上运行,因此在开始下一个循环迭代之前,您不能阻止等待第一个循环迭代完成,而不会严重影响页面可用性


解决方案取决于你真正需要什么。如果该示例与您所需要的非常接近,@Simon建议将
i
传递给您的异步进程,这是一个很好的建议。

JavaScript代码在单个线程上运行,因此您不能在不严重影响页面可用性的情况下,主要阻止等待第一个循环迭代完成后再开始下一个循环


解决方案取决于你真正需要什么。如果示例与您需要的非常接近,@Simon建议将
i
传递给您的异步进程,这是一个很好的建议。

for
循环在启动所有异步操作时立即运行到完成。当他们在将来某个时间完成并调用回调时,循环索引变量
i
的值将是所有回调的最后一个值

这是因为
for
循环在继续循环的下一次迭代之前不会等待异步操作完成,而且异步回调将在将来某个时候调用。因此,循环完成其迭代,然后在异步操作完成时调用回调。因此,循环索引是“完成”的,并且对于所有回调都位于其最终值

为了解决这个问题,您必须为每个回调单独保存循环索引。在Javascript中,实现这一点的方法是在函数闭包中捕获它。这可以通过创建一个专门用于此目的的内联函数闭包来实现(下面显示的第一个示例),也可以创建一个外部函数,将索引传递给它,并让它为您唯一地维护索引(下面显示的第二个示例)

从2016年起,如果您有一个完全符合规范的Javascript ES6实现,您还可以使用
let
来定义
for
循环变量,它将为
for
循环的每次迭代唯一定义(下面的第三个实现)。但是,请注意,这是ES6实现中的延迟实现特性,因此您必须确保您的执行环境支持该选项

使用.forEach()进行迭代,因为它创建了自己的函数闭包

someArray.forEach(function(item, i) {
    asynchronousProcess(function(item) {
        console.log(i);
    });
});
使用IIFE创建自己的函数闭包

var j = 10;
for (var i = 0; i < j; i++) {
    (function(cntr) {
        // here the value of i was passed into as the argument cntr
        // and will be captured in this function closure so each
        // iteration of the loop can have it's own value
        asynchronousProcess(function() {
            console.log(cntr);
        });
    })(i);
}
使用ES6
let

如果您有一个完全支持ES6的Javascript执行环境,您可以在
for
循环中使用
let
,如下所示:

var j = 10;
for (var i = 0; i < j; i++) {
    asynchronousProcess(i, function(cntr) {
        console.log(cntr);
    });
}
const j = 10;
for (let i = 0; i < j; i++) {
    asynchronousProcess(function() {
        console.log(i);
    });
}
这将确保一次只有一个对
asynchronousProcess()
的调用处于运行状态,并且
for
循环在每个调用完成之前都不会前进。这与之前所有并行运行异步操作的方案不同,因此它完全取决于您想要的设计。注意:
await
与承诺一起工作,因此您的函数必须返回一个承诺,该承诺在异步操作完成时被解析/拒绝。另外,请注意,要使用
wait
,必须将包含函数声明为
async

并行运行异步操作,并使用
Promise.all()
按顺序收集结果

 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);
 });
function someFunction(){
让承诺=[];
for(设i=0;i<10;i++){
promises.push(返回spromise()的异步进程);
}
返回承诺。全部(承诺);
}
someFunction()。然后(结果=>{
//按顺序排列的结果数组
控制台日志(结果);
}).catch(错误=>{
控制台日志(err);
});

for的
循环在所有异步操作启动时立即运行到完成。当他们在将来某个时间完成并调用回调时,循环索引变量
i
的值将是所有回调的最后一个值

这是因为
for
循环在继续循环的下一次迭代之前不会等待异步操作完成,而且异步回调将在将来某个时候调用。因此,循环完成其迭代,然后在异步操作完成时调用回调。因此,循环索引是“完成”的,并且对于所有回调都位于其最终值

为了解决这个问题,您必须为每个回调单独保存循环索引。在Javascript中,实现这一点的方法是在函数闭包中捕获它。这可以通过创建一个专门用于此目的的内联函数闭包来实现(下面显示的第一个示例),也可以创建一个外部函数,将索引传递给它,并让它为您唯一地维护索引(下面显示的第二个示例)

从2016年起,如果您有一个完全符合规范的Javascript ES6实现,您还可以使用
let
来定义
for
循环变量,它将为
for
循环的每次迭代唯一定义(下面的第三个实现)。但是,请注意,这是ES6实现中的延迟实现特性,因此您必须确保您的执行环境支持该选项

使用.forEach()进行迭代,因为它创建了自己的函数闭包

someArray.forEach(function(item, i) {
    asynchronousProcess(function(item) {
        console.log(i);
    });
});
Cre
for (i = 0; i < j; i++) {
    asycronouseProcess(function (i) {
        alert(i);
    }.bind(null, i));
}
for (i = 0; i < j; i++) {
    let k = i;
    asycronouseProcess(function() {
        alert(k);
    });
}
for (i = 0; i < j; i++) {
    asycronouseProcess(function(i) {
        return function () {
            alert(i)
        }
    }(i));
}
  var i;
  var j = 10;
  for (i = 0; i < j; i++) {
    await asycronouseProcess();
    alert(i);
  }
function asyncProcess() {
  return new Promise((resolve, reject) => {
    asycronouseProcess(()=>{
      resolve();
    })
  })
}