我有一个从MongoDB返回项目数组的函数:
var getBooks = function(callback){
Comment.distinct("doc", function(err, docs){
callback(docs);
}
});
};
现在,对于docs中返回的每个项目,我想执行另一个mongoose查询,收集特定字段的计数,将它们全部收集到counts
对象中,最后将其传递给{ {1}}:
res.render
如果我在getBooks(function(docs){
var counts = {};
docs.forEach(function(entry){
getAllCount(entry, ...){};
});
});
循环之后放置res.render
,它将在计数查询完成之前执行。但是,如果我将它包含在循环中,它将针对每个条目执行。这样做的正确方法是什么?
答案 0 :(得分:3)
我建议使用流行的NodeJS软件包async。它比工作/计数容易得多,another回答需要最终的错误处理。
特别是,我建议考虑each
(reference):
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
(reference):
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(...);
});
});
如果同时发出的请求太多,您可以使用mapLimit
或eachLimit
函数来限制同步异步猫鼬请求的数量。
答案 1 :(得分:1)
forEach
可能不是你最好的选择,除非你希望你getAllCount
的所有电话同时发生(也许你这样做,我不知道 - 或者就此而言,Node默认情况下仍然是单线程的,不是吗?)。相反,只需保留索引并重复docs
中每个条目的调用,直到完成为止。 E.g:
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
}
});
});
});
答案 2 :(得分:-1)
实际上,第一项上的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
});
});
});
这就是使用序列格式使用async构建的内容。