【问题标题】:Wait until all the function calls inside for-loop ends its execution - Javascript等到 for 循环内的所有函数调用结束其执行 - Javascript
【发布时间】:2023-08-30 04:40:01
【问题描述】:

我有一个函数,它在 for 循环中包含另一个函数调用。

outerFunction(){ 
    for (var j = 0; j < geoAddress.length; j++) {
         innerFunction(j);
    }
}

我需要等到对 innerFunction 的所有调用完成。如果我需要并行执行这些函数,如何在 JavaScript 中实现呢?

【问题讨论】:

  • 您能提供您的innerFunction 正文吗?
  • 所以innerFunction 被线程化了?
  • 假设 innerFunction 在异步中,使用“promises”,例如github.com/kriskowal/q
  • 您知道node.js 是单线程的,所以即使您异步执行innerFunction,每次也只会执行其中一个方法。?什么是内部函数?它会调用单独的服务或进程吗?它是如何工作的?
  • 我的内部功能是查询一个 mongoDB 数据库。根据 j ,内部函数从不同的 mongoDB 数据库中检索数据。最后,我需要汇总所有这些。

标签: javascript node.js loops asynchronous


【解决方案1】:

如果您不想为此使用外部库,您可以创建一个范围对象,例如 process,它会跟踪有多少 innerFunction 调用仍处于未决状态,并在等待时调用外部回调 cb完成了。

这样做的重点是您仍然可以获得异步执行的好处,但您只需确保您的代码在属于 outerFunction 的所有 innerFunction 实际完成之前不会执行下一部分:

outerFunction(function() {
    console.log("All done for outerFunction! - What you should do next?");

    // This block is executed when all innerFunction calls are finished.

});

JavaScript:

// Example addresses
var geoAddress = ["Some address X", "Some address Y"];

var innerFunction = function(geoAddress, process) { 

    // Your work to be done is here...
    // Now we use only setTimeout to demonstrate async method
    setTimeout(function() {

        console.log("innerFunction processing address: " + geoAddress);

        // Ok, we update the process
        process.done();   

    }, 500);

};

var outerFunction = function(cb) { 

    // Process object for tracking state of innerFunction executions
    var process = { 

        // Total number of work ahead (number of innerFunction calls required).
        count: geoAddress.length,

        // Method which is triggered when some call of innerFunction finishes  
        done: function() {

            // Decrease work pool
            this.count--;

            // Check if we are done & trigger a callback
            if(this.count === 0) { 
                setTimeout(cb, 0);
            }            
        }
    };

    for (var j = 0; j < geoAddress.length; j++) {
        innerFunction(geoAddress[j], process);
    }

};

// Testing our program
outerFunction(function() {
    console.log("All done for outerFunction! - What you should do next?");

    // This block is executed when all innerFunction calls are finished.

});

输出:

innerFunction processing address: Some address X
innerFunction processing address: Some address Y
All done for outerFunction! - What you should do next? 

这里是js fiddle example

干杯。

【讨论】:

    【解决方案2】:

    编辑 - 使用 Q Promise 库以节点方式做事

    如果您使用的是 Q Promise 库,请尝试以下操作:

    outerFunction(){
        var promises = [];
    
        for (var j = 0; j < geoAddress.length; j++) {
            deferreds.push(innerFunction(j));
        }
    
        Q.all(promises).then(function(){ 
            // do things after your inner functions run 
        });
    }
    

    即使您不使用这个特定的库,原理也是一样的。一个人应该让一个函数返回一个 Promise 或者像 Q.denodify 方法一样将它包装在一个 Promise 中,将所有调用推送到一个 Promise 数组,将所述数组传递给你的库的等效 .when() (jQuery) 或 .all () (Q Promise 库),然后在所有 Promise 都解决后使用 .then() 来做事。

    【讨论】:

    • 他正在使用 NodeJS,所以他不太可能会使用 jQuery。不过,还有其他延迟/承诺实现,such as q
    • 谢谢,马特。我编辑了答案来演示 Q 的 all() 方法的用户。
    【解决方案3】:
    outerFunction() { 
        var done = 0;
    
        function oneThreadDone() {
            done++;
            if (done === geoAddress.length) {
                // do something when all done
            }
        }
    
        for (var j = 0; j < geoAddress.length; j++) {
             setTimeout(function() { innerFunction(j, oneThreadDone); }, 0);
        }
    }
    

    并在 inner_function 内部调用 oneThreadDone() 函数(通过参数传递引用)

    【讨论】:

      【解决方案4】:

      查看异步库。 https://www.npmjs.org/package/async

      查看有关“同时”的文档。听起来它可以满足您的需求。 同时(测试,fn,回调)

      var count = 0;
      
      async.whilst(
      function () { return count < 5; },
      function (callback) {
          count++;
          setTimeout(callback, 1000);
      },
      function (err) {
          // 5 seconds have passed
      }
      

      );

      【讨论】:

      • 我认为这里的问题是,如果方法被两个不同的用户请求调用,那么这两个请求都会改变 count 的值,因为它被定义为 var count = 0;而不是属于某个对象实例。 (?)
      • 这个问题可以用async.forEach完美解决。你为什么用whilst发布不相关的代码?
      • 他没有遍历 geoAddress 数组中的每个对象,而是使用索引整数调用他的 innerFunction。 forEach 似乎不像 while 那样适合他的用例。
      最近更新 更多