繁体   English   中英

如何在Express.js和Mongoose中编写异步for-each循环?

[英]How to write an asynchronous for-each loop in Express.js and mongoose?

我有一个从MongoDB返回项目数组的函数:

var getBooks = function(callback){
    Comment.distinct("doc", function(err, docs){
            callback(docs);
        }
    });
};

现在,对于文档中返回的每个项目,我想执行另一个猫鼬查询,收集特定字段的计数,将它们全部收集在counts对象中,最后将其传递给res.render

getBooks(function(docs){
    var counts = {};
    docs.forEach(function(entry){
        getAllCount(entry, ...){};
    });      
});

如果将res.render放在forEach循环之后,它将在计数查询完成之前执行。 但是,如果我将其包括在循环中,它将为每个条目执行。 正确的做法是什么?

我建议使用流行的NodeJS包async 这比进行工作/计数要容易得多,并且另一个答案将需要最终的错误处理。

特别是,我建议考虑each参考 ):

getBooks(function(docs){
    var counts = {};
    async.each(docs, function(doc, callback){
        getAllCount(entry, ...);         
        // call the `callback` with a error if one occured, or 
        // empty params if everything was OK. 
        // store the value for each doc in counts
    }, function(err) {
       // all are complete (or an error occurred)
       // you can access counts here
       res.render(...);
    });      
});

或者您可以使用map参考 ):

getBooks(function(docs){
    async.map(docs, function(doc, transformed){
        getAllCount(entry, ...);         
        // call transformed(null, theCount);
        // for each document (or transformed(err); if there was an error); 
    }, function(err, results) {
       // all are complete (or an error occurred)
       // you can access results here, which contains the count value
       // returned by calling: transformed(null, ###) in the map function
       res.render(...);
    });      
});

如果同时请求太多,则可以使用mapLimiteachLimit函数来限制同时异步猫鼬请求的数量。

forEach可能不是您最好的选择,除非您希望对getAllCount所有调用并行发生(也许您知道,但我不知道,或者就此而言,Node默认仍然是单线程的,不是它?)。 相反,只保留一个索引并针对docs每个条目重复调用,直到完成为止似乎更好。 例如:

getBooks(function(docs){
    var counts = {},
        index = 0,
        entry;

    loop();

    function loop() {
        if (index < docs.length) {
            entry = docs[index++];
            getAllCount(entry, gotCount);
        }
        else {
            // Done, call `res.render` with the result
        }
    }
    function gotCount(count) {
        // ...store the count, it relates to `entry`...

        // And loop
        loop();
    }
});

如果您希望这些调用并行进行(或者您可以依赖于在单个线程中进行此调用),只需记住有多少未完成的调用,以便您知道何时完成:

// Assumes `docs` is not sparse
getBooks(function(docs){
    var counts = {},
        received = 0,
        outstanding;

    outstanding = docs.length;
    docs.forEach(function(entry){
        getAllCount(entry, function(count) {
            // ...store the count, note that it *doesn't* relate to `entry` as we
            // have overlapping calls...

            // Done?
            --outstanding;
            if (outstanding === 0) {
                // Yup, call `res.render` with the result
            }
        });
    });      
});

实际上,第一个项目上的getAllCount必须回调第二个项目上的getAllCount,...

两种方式:您可以使用框架,例如async: https : //github.com/caolan/async

或创建自己的回调链。 第一次写很有趣。

编辑目标是要有一种像我们写的那样进行的机制。

getAllCountFor(1, function(err1, result1) {
    getAllCountFor(2, function(err2, result2) {
        ...
            getAllCountFor(N, function(errN, resultN) {
                res.sender tout ca tout ca
            });
    });
});

这就是您将使用序列格式通过异步构造的内容。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM