【问题标题】:Nested Promises嵌套的 Promise
【发布时间】:2013-12-12 04:05:55
【问题描述】:

我有一个执行一系列异步操作的函数,这些操作依次执行其他异步操作的循环。我想知道什么时候一切都完成了。这似乎是让我全神贯注于承诺的好时机。

我在承诺前状态下的代码归结为类似这样(希望在简化过程中我没有使示例变得无用):

myClass.prototype.doMaintenance = function() {
    var types = ['choreType1', 'choreType2'];

    types.forEach(function(choreType) {
        // find all chores of the type with score 0 (need to be done) 
        redisClient.zrangebyscore('chores:'+choreType, 0, 0, function(err, chores) {
            if (!err) {
                chores.foreach(function(chore) {
                    doChore(chore, function(err, result){
                        // chore complete!
                    });
                })
            }
        });
    });
}

我通过一个循环,对循环中的每个项目进行异步数据库调用,并遍历返回的结果,对每个结果进行另一个异步调用。使用回调来传递所有家务都已完成的通知似乎充其量是丑陋的。因此,我的目标是:构建一个承诺,当所有的家务都完成后就会解决。

我面临两个困难。一个是简单地让 promise 语法正确。我将在下面向您展示我尝试过的内容。首先,一个可能导致此问题无法解决的问题:假设第一个数据库查询返回时只做一件苦差事。我(不知何故)把它作为整体“完成所有家务”承诺的一部分。现在我回去获取下一类家务的清单。如果同时完成了第一个家务怎么办? all-chores-done 承诺将在添加其余杂务之前得到满足并解决。

我在node.js 环境中使用Q 库。我使用Redis,但它可以是任何异步数据源。

myClass.prototype.doMaintenance = function() {
    var types = ['choreType1', 'choreType2'];
    var typePromises = [];

    types.forEach(function(choreType) {
        // find all chores of the type with score 0 (need to be done)
        Q.npost(redisClient, 'zrangebyscore', ['chores:'+choreType, 0, 0]).done(chores) {
            var chorePromises = [];
            chores.foreach(function(chore) {
                chorePromises.push(doChore(chore)); // doChore returns a promise
            });
            typePromises.push(Q.all(chorePromises));
        });
    });

    return Q.all(typePromises); // at this point, typePromises is empty. Bummer!
}

我一直在尝试构建的(还没有完全实现)是一个 Promise,它是 typePromises 的集合,而 typePromises 又是 chorePromises 的集合。

我认为我需要的是一个结构,上面写着“我保证会尽快给你做所有家务的承诺”。这开始让我的头爆炸。任何指导(包括完全使用不同的模式)将不胜感激。

【问题讨论】:

  • 我当前的(非node.js)项目也使用了promise系统。您能否确认您的方法至少在理论上有效,而忽略了“早期”完成家务的可能性?如果是这样,我只需在您的 doMaintenance 函数末尾添加另一个承诺,以确保在所有承诺完成之前完成循环。我使用它来将资源异步加载到系统中,它对我来说很好。

标签: javascript node.js promise q


【解决方案1】:

您正在异步构建typePromises 的列表 - 当您调用Q.all(typePromises) 时,它仍然是空的。相反,您需要立即返回一个可以立即收集到列表中的数据库结果的承诺。如果你还不知道这些 promise 的返回值是什么——不用担心,在 redis 结果到达后使用then 编写任务,例如获取Q.all(chorePromises)

我还建议使用 map 而不是在 each 循环中推送到数组 - 这也有助于确保立即构建承诺。

myClass.prototype.doMaintenance = function() {
    var types = ['choreType1', 'choreType2'];
    var typePromises = types.map(function(choreType) {
        // find all chores of the type with score 0 (need to be done)
        return Q.npost(redisClient, 'zrangebyscore', ['chores:'+choreType, 0, 0]).then(function(chores) {
            var chorePromises = chores.map(doChore); // doChore returns a promise
            return Q.all(chorePromises);
        }); // then returns a promise
    });
    return Q.all(typePromises);
}

【讨论】:

  • 感谢您的快速回复!我现在正在测试,通过语法工作(对我来说还不是第二天性)。现在在then 之后获取unexpected token {,但map 已经添加到我的曲目中。
  • 解决了语法问题,更接近应许之地。谢谢!我剩下的问题可能是因为有时没有家务可做。我认为在那种情况下我需要返回一个预先解决的承诺,也许?还是Q.all([]) 已经这样做了?
  • Afaik Q.all([]) does that,是的:-)
猜你喜欢
  • 2018-02-09
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
  • 2022-06-21
  • 2015-03-04
相关资源
最近更新 更多