如何在for循环中依次调用JavaScript函数?

4

我希望将每个项目传递到需要时间的函数中。但似乎JS函数是异步的。如何按顺序调用函数?(在上一个完成后将下一个项目传递给函数)

function main() {
    for (var i = 0; i < n ; i++) {
        doSomething(myArray[i]);
    }
}

function doSomething(item) {
    // do something take time
}

我的解决方案是递归调用函数。 但我想知道是否有其他不同的方法来解决这个问题?谢谢。

function main() {
    doSomething(myArray, 0);
}

function doSomething(item, i) {
    // do something take time
    doSomething(myArray, i + 1);
}

据我所知,JavaScript中的for循环和函数调用是同步的,所以必须有其他原因使函数变成异步的。也许是函数内部的某些内容导致了这种情况。 - Andros Rex
抱歉没有提到,我的代码是在一个node.js服务器上运行的。这就是为什么这个函数是异步的原因吗? - Aaron
1
我脑海中浮现出myArray.forEach(doSomething)这个方法。 - Malk
函数不会仅仅因为在node.js上就变成异步的。你的函数实际上是做什么的?异步函数通常具有回调机制或返回一个Promise,因此您可以使用它来协调后续的调用。 - nnnnnn
嗨 @nnnnnn,这个函数做的事情类似于发送 HTTP POST 请求,并且我有一个回调函数。我的解决方案是将 doSomething(myArray, i + 1); 放在回调函数内部。 - Aaron
这是一个相当常规的做法。(请注意,这实际上并不是一个真正的递归调用,因为doSomething()并没有调用自身,而是在完成后稍后会调用回调函数,然后再从那里调用doSomething() - 类似伪递归。) - nnnnnn
2个回答

6

在JavaScript中,从2020年开始,for循环已经支持async/await。你可以返回一个Promise,然后在for循环内部使用await来等待该Promise的执行。这将导致循环按顺序执行,即使进行了长时间的操作。

function randomSleep(ms, seed=10) {
    ms = ms * Math.random() * seed;
    return new Promise((resolve, reject)=>setTimeout(resolve, ms));
} 
async function doSomething(idx) {
  // long running operations
  const outcome = await randomSleep(500);
  return idx;
}   
const arrItems = ['a','b','c','d'];
for(let i=0,len=arrItems.length;i<len;i++) {
  const result = await doSomething(i);
  console.log("result is", result)
}

在这里阅读有关for循环和forEach循环中async和await的更多信息:https://zellwk.com/blog/async-await-in-loops/


0
如果你想在前一个完成后将下一个项目传递给函数,你可以尝试使用Promise,就像这样。
var Q = require('q'); 
var promise;
main();
function main() {
     promise = doSomethingPromise(0)
    for (var i = 1; i < 10 ; i++) {
        (function (i) {
            promise = promise.then(function (res) {
                return doSomethingPromise(res + ' ' + i)
            });
        })(i)

    }
}

function doSomethingPromise (item) {
   var d = Q.defer();
      d.resolve(doSomething(item));
   return d.promise;
}

function doSomething(item) {
    // do something take time
    console.log('doSomething', item);
    return item;
}

它可以按顺序调用您的函数。


嗨chenkehxx,我尝试了你的答案。但是看起来item[1]到item[item.length-1]都卡在Q.defer()这一行。 - Aaron
可以让我看看你的所有代码吗?我不运行我的代码。它只是伪代码。 - chenkehxx
嗨chenkenhxx,我的代码就像你在这里写的一样。 - Aaron
@Aaron,我已经更新了我的代码,你可以再试一次。 - chenkehxx
嗨chenkehxx,我尝试了你修改后的答案,但日志显示只有第一个项目在doSomething函数中运行。 - Aaron
最后,我在for循环中创建了一个函数数组,并使用async.series来实现我想要的功能。 - Aaron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接