Nodejs中forEach中有个异步函数,如何等异步函数执行完毕之后再执行整个函数的callback
Nodejs中forEach中有个异步函数,如何等异步函数执行完毕之后再执行整个函数的callback
exports.getComments=function(query,skip,limit,callback){
Comment.find(query).sort({create_time:-1}).skip(skip).limit(limit).exec(function(error,comments){
if(error){
callback(error,null);
}
comments.foreach(function(index,comment){
Comment.find({reply_ID:comment.comment_ID}, function(err, replys){
comment.reply=replys;
});
});
callback(error,comments);
})
我的想法是将comment增加一个reply属性,然后再返回comments集合,但由于Comment.find是异步的,故向各位大虾求助,提供点解决方案的,初学,求照顾
在Node.js中使用forEach
循环处理异步操作时,由于forEach
本身是同步的,而其中的异步函数(如Comment.find
)是异步的,这会导致回调函数在所有异步操作完成之前就被调用。为了解决这个问题,我们可以使用一些方法来确保所有的异步操作都完成后再执行回调。
一种常见的方法是使用async
库中的eachSeries
或for await (const item of array)
(对于支持async/await
的环境)。这里我将展示如何使用async
库的eachSeries
来解决这个问题。
首先,你需要安装async
库:
npm install async
然后,你可以修改你的函数如下:
const async = require('async');
exports.getComments = function(query, skip, limit, callback) {
Comment.find(query).sort({ create_time: -1 }).skip(skip).limit(limit).exec(function(error, comments) {
if (error) {
callback(error, null);
return;
}
// 使用 async.eachSeries 来确保每个异步操作按顺序完成
async.eachSeries(comments, function(comment, eachCallback) {
Comment.find({ reply_ID: comment.comment_ID }, function(err, replys) {
if (err) {
eachCallback(err); // 如果有错误,停止后续操作
return;
}
comment.reply = replys;
eachCallback(); // 完成当前迭代
});
}, function(err) {
// 所有异步操作完成后的回调
if (err) {
callback(err, null);
} else {
callback(null, comments);
}
});
});
}
在这个例子中,我们使用了async.eachSeries
来确保每个异步操作(即Comment.find
)在继续下一个操作之前已经完成。eachSeries
接受两个参数:一个数组和一个迭代函数。迭代函数接收当前元素、一个回调函数作为参数。当所有的异步操作完成时,最后一个参数是一个最终的回调函数,它会在所有异步操作完成后被调用。
这样可以确保所有的评论及其回复都被正确加载,并且只有在所有异步操作完成后才会调用外部的callback
函数。
谢谢你的回答,但这样的话貌似会触发N次callback
我的解决思路:
Comment.find(query).sort({create_time:-1}).skip(skip).limit(limit).exec(function(error,comments){
if (comments.length === 0) {
return callback(error, []);
}
var proxy = new EventProxy();
var done = function () {
return callback(error, comments);
};
proxy.after('reply', comments.length, done);
comments.forEach(function(comment,index){
Comment.find({reply_ID:comment.comment_ID},function(error,replys){
comment.reply=replys;
proxy.trigger('reply',replys);
})
})
});
感觉应该可以吧
那你能不能说一下你这段代码到底是什意思?比如comment 是什么。 我们才能给你答案。没头没尾的贴出代码谁能看懂。
not tested, might work:
var ln = comments.length
comments.foreach(function(index, comment) {
Comment.find({ reply_ID: comment.comment_ID}, function(err, replys) {
comment.reply = replys;
ln --
if (ln === 0) {
callback(null, comments);
}
});
});'
这种方式我试过了,貌似不行,我用EventProxy解决了,参考了一下咱们论坛的源码
我这个就是一个评论,回复模块,就像咱们现在这个club一样,你评论就是comment,我再回复你就是reply,关联id就是reply_id=comment_id,评论和回复都放在了同一个表里面
为何不写在存储过程里
MongoDB的存储过程还真不清楚