Node.js:async.series 中的 forEach

Posted

技术标签:

【中文标题】Node.js:async.series 中的 forEach【英文标题】:Node.js: forEach inside async.series 【发布时间】:2013-10-28 19:26:27 【问题描述】:

我开始为工作开发我的 node.js 应用程序,但我不能“认为异步”。 在我的函数中,我必须做一个查询,并且对于每一行我都必须做另一个查询来计算最终结果并创建我的 json。 我尝试这样做:

async.series([
    function(callback) 
            db.myCannedResponseList(req.params.websiteid, function(err,questions) 
                if (err) return callback(err);
                ...
                callback();
            );
        ,
    function(callback) 
            async.forEachSeries(temp,function(quest,callback) 
                    db.getCannedAnswer(quest.id, function(err,answers) 
                         console.log(answers);
                    );
            , function(err) 
                if (err) return next(err);
            );
            callback();
        
    ],
        function(err)  
            if (err) return next(err);
            res.json(output);
    );

但是有一个问题:getCannedAnswer的结果显示在res.json(output)之后。 我该如何解决?

【问题讨论】:

【参考方案1】:

您需要在forEachSeries 完成后调用回调。您还需要调用传递给forEachSeries 处理函数的回调:

async.forEachSeries(temp, function(quest, callback2) 
  db.getCannedAnswer(quest.id, function(err, answers) 
    console.log(answers);
    // call the callback for forEachSeries so it can proceed:
    callback2(); 
  );
, callback); // forEachSeries is done here, call the callback for async.series

【讨论】:

可能只需要传递callback 来代替匿名的function(err)。它会在return next(err); 上出现throw,因为next 无论如何都不存在(除非它是在给定的sn-p 之外定义的)。【参考方案2】:

您的异步函数是嵌套的,因此需要成为您的回调函数。

这是一种方法:

    async.series([
        //async.apply(db.myCannedResponseList,req.params.websiteid), // This is equivalent to the first function below
        //db.myCannedResponseList(req.params.websiteid,callback), // This is equivalent too
        function(callback) 
            db.myCannedResponseList(req.params.websiteid, callback);
        ,    
        function(callback) 
            // I'm not sure forEach is the best choice here
            // since it's callback isn't called with all the results so it won't be able to be forwarded...
            // Personally, I use async.times for something like this.
            async.times(temp.length,function(i,next) 
                db.getCannedAnswer(temp[i].id,next);
            ,callback)
        
     ],function(err)  
          if (err) return next(err);
          res.json(output);
    );

我不确定这个函数应该做什么,但如果你在async.series 中遇到错误,你应该调用res.json(500,error) 或者在成功时不调用res

一个好的方法是完全分离这个函数并让它在完成时调用另一个回调。然后你会在那里打电话给res

此外,您可以传递一个对象,而不是将数组传递给async.series,以便将结果命名空间。

完整示例:

    function getCannedStuff(data,callback)
        async.series(
            list : async.apply(db.myCannedResponseList,data.websiteid),
            answer : function(cb) 
                async.times(data.temp.length,function(i,next) 
                db.getCannedAnswer(data.temp[i].id,next);
                ,cb)
            
        ,callback);  
    

然后从另一个模块调用函数:

    getCannedStuff(
        websiteid: req.params.websiteid,
        temp:temp
    ,function(error,results) 
        console.log(results.list);
        console.log(results.answer);
        if(err) return res.json(500,error : error);
        res.json(results)
    );

您应该决定是否要控制getCannedStuff 内部或外部的错误,但这是一个很好的方法来传递它们,而不是一直这样做if(err) 来查看它们是否发生。

【讨论】:

在最终回调中出现错误时调用 next(err) 对于定义了应用程序范围的错误处理程序的 Express 应用程序来说是非常标准的行为。 @robertklep 是的。只是想用这个例子来说明我的观点

以上是关于Node.js:async.series 中的 forEach的主要内容,如果未能解决你的问题,请参考以下文章

node.js async.series 是它应该如何工作的?

Node.js中流程控制

使用 Node.js、Async 和 Formidable 处理错误

使用 Node.js、Async 和 Formidable 处理错误

Node.js异步库async

node.js async.js nextTick vs setImmediate