【问题标题】:node.js deferred misunderstandingnode.js 延迟误解
【发布时间】:2014-04-04 16:20:59
【问题描述】:

我正在学习 q.js 并尝试在它的帮助下同时查询 3 个集合(避免回调地狱):

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

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

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

call() 是导出承诺的简写

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 的回调执行晚于将 Promise 推送到数组。 我相信它可以通过使用result.toArray() 而不是.each 来完成,但是如何在.each 循环的帮助下完成呢?

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

【问题讨论】:

  • 你从哪里得到each()?你用 Javascript 函数forEach() 试过了吗?它可能对你更有效。另外,我不确定我是否遵循了result.each()function (err,data) 调用,您的each 调用是否出错?
  • 你从哪里得到每个 deferred 变量?
  • 添加了询问的信息。
  • 知道了,谢谢 - 我不是 mongo 人,但如果我正确地遵循这一点,我认为您的一般问题是 .each() 方法正在异步执行,但不是一部分你的承诺计划。您可能想要使用Q.ninvokeQ.denodeify 或一些类似的策略,以便each() 返回一个承诺。另外,我知道您显然在删除一些代码,但正如所写,您只有一个 deferred 正在操作。在你的循环中,你只是用相同承诺的多个副本填充数组,这在你正在解决的前一行中。
  • 你说得对,.each() 是异步的。无法理解 Q 函数(.fcall.ncall 等)。你能推荐一个关于这个库的好教程或详细手册吗?我对它的主页不满意。

标签: node.js promise deferred q


【解决方案1】:
var deferred = Q.defer();
…
deferred.resolve(…);
…
deferred.resolve(…);

call() 是导出承诺的简写

那是行不通的!您需要为您想要的每个承诺创建一个新的 deferred。但是,你shouldn't use Deferreds anyway!相反,请使用 many Node callback helper functions


如您所见, .each 的回调在将 Promise 推送到数组之后执行。我相信它可以通过使用 result.toArray() 而不是 .each 来完成,但是如何在 .each 循环的帮助下完成呢?

它不能,除非你事先知道each 被调用的频率以及需要创建多少个promise。 Q.all 在这里有点用处,因为 Promise 不是一次创建并并行执行它们的任务 - 相反,它们是一个流。

你真的应该在这里使用toArray,来获得一个你用来解决承诺的回调。

嗯,有一种方法,但它比toArray 丑而且效率低。你可以让一个 deferred 永远等待,并且只通过对流的其余部分的承诺来解决。

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;
}

【讨论】:

  • 感谢您的关注。我会尝试.toArray()。难道someArray.forEach(callbackFunction()) 是同步执行的吗?在 mongodb 驱动程序中,.each() 被记录为异步。
  • 是的,forEach != each
猜你喜欢
  • 2012-08-08
  • 2012-08-27
  • 2021-03-28
  • 1970-01-01
  • 1970-01-01
  • 2015-06-22
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
相关资源
最近更新 更多