嵌套的承诺

时间:2013-12-11 18:19:23

标签: javascript node.js promise q

我有一个执行一系列异步操作的函数,这些异步操作又执行其他异步操作的循环。我想知道一切都完成了。这似乎是让我的头脑缠绕在承诺上的好时机。

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

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语法。我会告诉你我在下面尝试过的东西。首先,一个可能导致这个无法解决的问题:说第一个数据库查询返回一个单一的杂项。我(不知何故)把它作为整体“完成所有家务”承诺的一部分。现在我回去找一份下一类家务清单。如果在此期间完成第一项杂务怎么办?在添加其他杂务之前,将完成所有琐事的承诺,并将解决。

我在Q环境中使用node.js库。我使用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!
}

我一直在努力构建(还不是那里)是一个承诺,它是typePromises的集合,而typePromises又是chorePromises的集合。

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

1 个答案:

答案 0 :(得分:4)

您正在异步构建typePromises列表 - 当您致电Q.all(typePromises)时,它仍为空。相反,您需要立即返回数据库结果的承诺,您可以立即将其收集到列表中。如果您还不知道这些承诺的返回值是什么 - 不用担心,请使用then来组成任务,例如在redis结果到达后获取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);
}