gpt4 book ai didi

javascript - javascript for 循环内的异步过程

转载 作者:行者123 更新时间:2023-11-28 04:19:54 24 4
gpt4 key购买 nike

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

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

asynchronousProcess(callbackFunction() {
alert(i);
});
}

我试图显示一系列显示数字 0 到 10 的警报。问题是,当回调函数被触发时,循环已经经过了几次迭代,并且显示了更高的值 i 。关于如何解决这个问题有什么建议吗?

最佳答案

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

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

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

截至 2016 年,如果您有完全符合规范的 ES6 Javascript 实现,您还可以使用 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);
}

创建或修改外部函数并向其传递变量

如果您可以修改 asynchronousProcess() 函数,那么您只需将值传递到其中,然后让 asynchronousProcess() 函数将 cntr 返回到回调,例如这个:

var j = 10;
for (var i = 0; i < j; i++) {
asynchronousProcess(i, function(cntr) {
console.log(cntr);
});
}

使用 ES6 let

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

const j = 10;
for (let i = 0; i < j; i++) {
asynchronousProcess(function() {
console.log(i);
});
}
像这样在 for 循环声明中声明的

let 将为循环的每次调用创建一个唯一的 i 值(这就是你想要的)。

使用 Promise 和 async/await 进行序列化

如果您的异步函数返回一个 Promise,并且您希望序列化异步操作以依次运行而不是并行运行,并且您正在支持 async 的现代环境中运行>等待,然后你就有更多选择。

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);
}
}

这将确保一次只有一次对 asynchronousProcess() 的调用,并且 for 循环在每个调用完成之前都不会前进。这与之前所有并行运行异步操作的方案不同,因此它完全取决于您想要的设计。注意:await 使用 Promise,因此您的函数必须返回一个在异步操作完成时已解决/拒绝的 Promise。另请注意,为了使用 await,包含函数必须声明为 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);
});

关于javascript - javascript for 循环内的异步过程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45527059/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com