当前位置: 首页 > 面试题库 >

javascript for循环内的异步处理

阙博容
2023-03-14
问题内容

这个问题已经在这里有了答案

循环内的JavaScript封闭-简单的实际示例 (44个答案)

2年前关闭。

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

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

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

我正在尝试显示一系列警报,显示从0到10的数字。问题是,当触发回调函数时,循环已经经历了几次迭代,并且显示了更高的值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);
}

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

如果可以修改该asynchronousProcess()函数,则可以在其中传递值,然后asynchronousProcess()将cntr函数返回回调,如下所示:

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

使用ES6let

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

const j = 10;
for (let i = 0; i < j; i++) {
    asynchronousProcess(function() {
        console.log(i);
    });
}

let在这样的for循环声明中声明的代码i将为每次循环调用创建一个唯一的值(这是您想要的)。

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

如果您的异步函数返回了一个Promise,并且您希望序列化异步操作以使其依次而不是并行运行,并且您正在支持async和的现代环境中运行await,那么您将有更多选择。

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该函数,必须声明contains函数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);
 });


 类似资料:
  • 我对一个异步函数有点拘泥于此。 我要完成的是创建一个batchProcessing函数(batchGetSubs),它将循环访问一组文件,读取一个ID,然后发出一个API请求,等待一个响应(问题),然后用格式化的数据写入一个新文件。 问题--我尝试了异步和等待,以及推送承诺和尝试使用承诺.所有这些都是为了等待承诺的解决,但没有成功。当前的行为是,在API调用实际返回所有数据之前,我获取Promis

  • 问题内容: 我需要一个等待异步调用然后继续的循环。就像是: 我该怎么办?你有什么想法? 问题答案: 如果阻止脚本和浏览器,则无法在JavaScript中混合使用同步和异步。 您需要在此处采用完整的事件驱动方式,幸运的是我们可以将丑陋的东西藏起来。 编辑: 更新了代码。 这将为我们提供一个异步方法,您当然可以进一步修改它,例如使用一个检查循环条件的函数等。 现在进行测试: 并输出:

  • 问题内容: 我有这个脚本: 但被警告两次,而不是那么。 有没有一种方法可以传递而不将函数编写为字符串? 问题答案: 您必须为每个超时功能安排一个单独的“ i”副本。 如果您不做这样的事情(同一想法还有其他变体),那么每个计时器处理程序函数将 共享 相同的变量“ i”。循环结束后,“ i”的值是多少?3!通过使用中间函数,将 复制 变量的值。由于超时处理程序是在该副本的上下文中创建的,因此它具有自己

  • 问题内容: 我是Node的新手,并试图确保我对JSON驱动的Web应用程序使用了合理的设计。 我已经在Redis中存储了一堆数据,并且正在通过node检索它们,并将结果从Redis中流出来。这是我正在做的一个很好的例子: 本质上,我是从Redis获取一组密钥,然后请求每个密钥,然后将结果流式传输到半手动创建的JSON(来自Redis的字符串已经在JSON中)。现在,这很好用,但是我不禁会以为i =

  • 问题内容: 我是这个Node.js的新手..我对此回调有点困惑..在我的应用程序中,我在for循环内调用异步函数调用,我想我的问题是在得到异步调用响应之前, for循环被循环。 我的代码: 搜索功能代码: 我想在成功执行1个搜索功能后执行for循环,我想我必须使用async for loop。请指导我解决此问题。 问题答案: 我将您的代码示例简化为以下几行,以使您更容易理解该概念。 先前代码的问题

  • 本文向大家介绍JavaScript 异步等待循环,包括了JavaScript 异步等待循环的使用技巧和注意事项,需要的朋友参考一下 示例 在循环中使用异步等待时,您可能会遇到其中一些问题。 如果您只是尝试在内部使用await forEach,则会抛出Unexpected token错误。 这是因为您错误地将箭头功能视为一个块。该await会在回调函数,这是不是上下文async。 解释器可以防止我们