【发布时间】: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