node.js推迟了误解

我正在学习q.js并试图同时查询3个集合(避免callback地狱):

var Q = require('q') var deferred = Q.defer(); 

users()是db.collection.find()的包装器

 var users = function (){ Auth.listUsers({role:'user'}, call) return deferred.promise } 

call()是导出promise的简写

 var call = function (err,data){ if (err) { deferred.reject(err); } else { deferred.resolve(data); } } 

loop()是主循环,它获取游标并循环通过条目

 var loop = function (result) { var list = [] var promises = []; result.each(function (err,data){ if (err) { deferred.reject(err); } else { deferred.resolve(data); promises.push(deferred.promise) console.log('promises_:', promises) // <- internal } }) console.log('promises:', promises) // <- external return Q.all(promises) } 

码:

 users() .then(loop) .then(function(ful){ console.log('ful:', ful); // <- here should come the queries to other collections }) 

最后的控制台日志结果:

 promises: [] //external is empty ful: [] promises_: [ [object Object] ] // internal is being filled promises_: [ [object Object], [object Object] ] 

正如你所看到的, .each的callback比向数组推送promise晚。 我相信可以通过使用result.toArray()而不是.each来完成,但是如何在.each循环的帮助下.each呢?

结果是由db.collection.find()调用( http://mongodb.github.io/node-mongodb-native/api-generated/collection.html#find )后的mongodb驱动程序返回的游标。

 var deferred = Q.defer(); … deferred.resolve(…); … deferred.resolve(…); 

call()是导出promise的简写

这是行不通的! 您需要为每个所需的承诺创build一个新的延期。 不过,你不应该使用Deferred s ! 相反,使用许多 节点callback助手function 。


正如你所看到的,.each的callback比向数组推送承诺要晚。 我相信可以通过使用result.toArray()而不是.each来完成,但是如何在.each循环的帮助下完成呢?

它不能,除非你事先知道each被调用的频率以及需要创build多less个承诺。 Q.all在这里有点用处,因为promise不是一次创build的,而是并行地执行它们的任务 – 相反,它们是一个stream。

你真的应该使用toArray在这里,得到一个callback,你解决承诺。

那么,有一种方法,但它比toArray更丑陋,效率更低。 你可以有一个延迟,将永远等待,只解决与stream的其余部分的承诺。

 function loop(result) { var deferred = Q.defer(); result.each(function (err,data){ if (err) { deferred.reject(err); } else if (data == null) { deferred.resolve([]); // end of the stream } else { var nextDeferred = Q.defer(); deferred.resolve(nextDeferred.promise.then(function(rest) { return [data].concat(rest); })); deferred = nextDeferred; } }) return deferred.promise; }