正确使用异步(使用forEach)

时间:2013-12-17 10:58:45

标签: javascript asynchronous foreach

所以我有一大堆嵌套的异步代码一起运行,这一切似乎都没问题,除非我到达它的末尾。我在序列块中的最后一个函数是forEach:然后进入async.parallel

管理以跟踪以下未按顺序运行的块:

async.forEach(array, function(elem, callback) {
      async.parallel([
          function(callback) {
              database-call-A(elem, unction(err, data)  {
                    if(err){
                        console.log("error on first parallel");
                        callback({err: false}); // will break out
                    } else {
                        elem.c = data;
                        callback();
                    }
              });
          },
          function(callback) {
               database-call-B(elem, function(err, data)  {
                    if(err){
                        console.log("error on first parallel");
                        callback({err: false}); // will break out
                    } else {
                        elem.c = data;
                        callback();
                    }
              });
          } 
       ]); // end async.parallel 

       // if forEach needs a callback after every iteration (which I think it does?)
       console.log("PRINTS N TIMES - ONCE FOR EVERY ITERATION");
       callback(); // both parallel functions have run, call back forEach

 }); // end forEach

 console.log("Donions - prints when finished");

当我通过在任何地方抛出打印语句来测试此代码时,我注意到" PRINTS N TIMES ..."跑了N次,然后我得到了#34;捐款......"然后我做了一些事情();和其他东西();开始在我的async.parallel中调用。

为什么我的forEach在没有等待来自async.parallel的回调的情况下进行迭代?

2 个答案:

答案 0 :(得分:3)

首先,没有async.forEach,但有async.each功能。 async.parallel函数将同时执行所有任务,然后执行回调(如果已定义)。

在您的源代码中,callback函数将在async.parallel执行后立即执行,而不是在所有函数返回后执行。我建议你阅读documentation

如果要在调用所有并行函数的回调后执行callback,则应将forEach的回调作为第二个参数传递给async.parallel函数,在函数数组之后。此外,您应该将回调传递给databaseCallAdatabaseCallB,从而使它们在完成后调用它们的回调,这样它们就不会过早执行。

async.each(array, function(elem, callback) {
    async.parallel([
        function(cb) {
            databaseCallA(cb);
            // if you have called the cb here, the `async.parallel` function would "think" that the databaseCallA has finished, even though it may not have started yet.
        },
        function(cb) {
            databaseCallB(cb):
        } 
    ], callback);
});

您应该修改数据库调用函数以接受回调参数,并让它们在完成工作后调用回调函数。

异步调用的重点是在等待作业完成时释放其他作业的资源 - 您的代码将继续执行,但您可以使用回调或某种基于事件的通知来通知其他人您的异步工作已经完成。

修改

在所有并行调用完成后执行某些操作:

async.each(array, function(elem, callback) {
    async.parallel([
        function(cb) {
            // I use the setTimeout function to intentionally
            // delay the response
            setTimeout(function() {
                // the first cb parameter is error, the second is result 
                // in case there was no error
                cb(undefined, 'a');
            }, 500);
        },
        function(cb) {
            setTimeout(function() {
                cb(undefined, 'b');
            }, 300);
        },
        function(cb) {
            setTimeout(function() {
                cb(undefined, 'c');
            }, 800);
        }
    ], function(err, results) {
        // this will be executed only after all three cb's are executed. In
        // this case, after about 800ms. The results variable will be an 
        // array containing the resuts passed to each cb. In this case it
        // will  be ['a', 'b', 'c'].

        // you could call the main callback here
        callback();
    });
}, function(err) {
    // this callback will be executed either after everything was done,
    // or if an error has occurred.
    if (err) {
        handleError(err);
        return;
    }

    // this should be executed after all `each` and `parallel` calls
    // have finished. In this case, it should also be after about 800ms
    // from the start, since everything was executed in parallel
    console.log('finished');

    // now you are sure everything was done, do something afterwards
    after();
});

// this will be executed immediately so don't put anything here
// that depends on the outcome of the async calls above
console.log('test');

答案 1 :(得分:0)

我不确定这个答案,但根据异步文档,我认为你必须这样做:

async.forEach(array, function(elem, callback) {
    async.parallel([
      function(callback) {
          database-call-A();
          callback();
      },
      function(callback) {
          database-call-B():
          callback(); // callback for second parallel function
      } 
   ], function(err,result) {
         // this code is executed when paralles functions ends
         console.log("PRINTS N TIMES - ONCE FOR EVERY ITERATION");
         callback(); 
   }); // end async.parallel 

 }); // end forEach

问候。