什么's是在Node.js中链接异步函数的正确方式
What's the proper way of chaining async functions in Node.js?
我有一个有趣的案例,我需要使用Mongoose在MongoDB中进行一些查询,但在我完成所有查询之前,响应已经返回。
我有两种文档类型,列表和项目。在一个特定的调用中,我需要获取特定用户的所有列表,然后对每个列表进行迭代,获取所有项目,并在返回之前将它们附加到适当的列表中。
List.find({'user_id': req.params.user_id}, function(err, docs){
if (!err) {
if (docs) {
var results = [];
_und.each(docs, function(value, key) {
var list = value.toObject();
list.items = [];
Item.find({'list_id': value._id}, function(err, docs) {
if (!err) {
_und.each(docs, function(value, key) { list.items.push(value.toObject()); });
results.push(list);
}
else {
console.log(err);
}
});
});
res.send(results);
(_und是我导入下划线.js的方式)
很明显,问题是回调,由于有多个循环,我无法在回调中返回。
也许在这种情况下,我需要提前获得计数,并在每次迭代时进行检查,以决定何时返回结果。不过这看起来并不优雅。
代码解决方案
首先,问题在于代码。您在Item.find查询完成之前发送结果。你可以很容易地修复这个
var count = docs.length + 1;
next()
_und.each(docs, function(value, key) {
var list = value.toObject();
list.items = [];
Item.find({
'list_id': value._id
}, function(err, docs) {
if (!err) {
_und.each(docs, function(value, key) {
list.items.push(value.toObject());
});
// push asynchronous
results.push(list);
next()
}
else {
console.log(err);
}
});
});
function next() {
--count === 0 && finish()
}
function finish() {
res.send(results)
}
最简单的方法是引用计数,默认为文档数。然后,每次你完成一个项目,你就调用next
,并将计数递减一。
一旦你完成了所有项目的获取,你的计数应该为零。请注意,我们执行.length + 1
并立即调用next
。这与并没有文件的情况相反,否则文件将毫无作用。
数据库解决方案
最好的解决方案是正确使用mongo。你不应该在你的代码中做一个有效的联接,这是非常缓慢和低效的。您应该有一个嵌套的文档,并取消对列表的规范化。
所以list.items = [Item, Item, ...]
除此之外,避免mongose,它效率低下,使用本地mongo驱动程序。
我与此模块一起使用:https://github.com/caolan/async
相关文章:
- 如何在异步函数中使用javascript对象
- 调用后不异步Ajax忽略函数
- javascript函数中的异步与同步.(Node.js)
- Meteor:异步函数回调异常:onAfterAction
- 从框架中的函数异步加载 Javascript
- 为什么在定义回调/侦听器函数(异步消息传递,port.on)后没有立即设置全局变量
- 将javascript变量传输到插件函数(异步URL)
- 如何从 JavaScript 调用 JQuery 函数(异步调用后)
- 与其他变换函数异步制作不透明度动画
- 两个异步模块函数异步工作
- durandal激活函数异步代码
- 无法使我的示例函数异步
- 当内部函数异步执行某些操作时,如何从外部函数的回调返回值
- Javascript -使函数异步
- 如何使这个同步递归函数异步
- Promise.then()但函数异步运行
- 使用setimeout使命名函数异步化
- Javascript esriRequest (dojo)在函数异步问题
- 返回嵌套函数(异步)
- 我如何使这个JS函数异步