嵌套承诺

Nested Promises

本文关键字:承诺 嵌套      更新时间:2023-09-26

我有一个函数,它执行一系列异步操作,然后执行其他异步操作的循环。我想知道什么时候一切都完成了。这似乎是一个让我沉浸在承诺中的好时机。

我的代码在promise之前的状态可以归结为这样的东西(希望在简化过程中我没有让这个例子变得无用):

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语法正确。我将在下面向您展示我尝试过的内容。首先,一个可能导致此问题无法解决的问题是:假设第一个数据库查询返回时只有一件家务事。我(不知怎么的)把它作为整体"完成所有家务"承诺的一部分。现在我回过头来看看下一类家务活的清单。如果在此期间第一件家务事完成了呢?在添加其他家务之前,所做的所有家务承诺都会得到满足,并会得到解决。

我在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的集合,反过来又是chorePromises集合。

我想我需要的是一个结构,上面写着"我保证一有空就帮你完成所有家务。"这开始让我大吃一惊。任何指导(包括完全使用不同的模式)都将不胜感激。

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

我还建议使用map,而不是在each循环中推送一个数组——这也有助于确保立即构建promise。

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