我有一个执行一系列异步操作的函数,这些异步操作又执行其他异步操作的循环。我想知道一切都完成了。这似乎是让我的头脑缠绕在承诺上的好时机。
我在承诺前状态下的代码归结为类似的东西(希望在简化过程中我没有使示例无用):
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的集合。
我认为我需要的是一个结构,上面写着“我保证尽快为你做好所有家务的承诺。”这开始使我的头爆炸。任何指导(包括完全使用不同的模式)将不胜感激。
答案 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);
}