我似乎无法找到解决此问题的正确方法。我有一大堆的承诺,并且在其中一个解析器中,我想暂停并在数组上做一系列的工作(使用promises),我不希望这个实际解决,直到一系列的承诺有完成。这个例子似乎让我非常接近,但我想我可能已经创建了一个反模式。
http://taoofcode.net/promise-anti-patterns/
// async_series.js
// example of using reduce and promises and closure to create async results in series
var q = require('Q');
var results = [1, 2, 3, 4, 5];
function workCollection(arr) {
return arr.reduce(function(promise, item, index) {
return promise.then(function(result) {
return (function(i, r, idx){
setTimeout(function(){
console.log('item', i, 'result', r, 'index', idx);
}, 1000 * idx);
return true
})(item, result, index);
});
}, q().then(function(){return true}));
}
q()
.then(function(){
console.log('start');
})
.then(function(){
workCollection(results)
})
.then(function(){
console.log('done');
})
.catch(function(err){
console.log(err);
});
有点工作,但输出是:
start
done
item 1 result true index 0
item 2 result true index 1
item 3 result true index 2
item 4 result true index 3
item 5 result true index 4
与此相反(预期):
start
item 1 result true index 0
item 2 result true index 1
item 3 result true index 2
item 4 result true index 3
item 5 result true index 4
done
建议非常感谢。 Plz在投票前发表评论。
答案 0 :(得分:1)
您可以使用promise.all()
实现此目的。只需将每个数组promises推送到一个数组中(通常名为deferred
),然后返回promise.all(deferred)
此处的文档:https://github.com/kriskowal/q/wiki/API-Reference#promise-for-array-methods
<强>更新强>
我创建了一个使用deferred
的词,而不是编辑你的小提琴,这是你在这种情况下应该使用的。 https://jsfiddle.net/twler/aujqcmhv/1/
希望它能清除一些关于promise对象的内容,因为它们可能令人困惑。
答案 1 :(得分:1)
我认为您在done
之后立即收到start
,因为您未在当时返回workCollection(results)
的结果,因此立即通过undefined
解决问题。试试这个
.then(function(){
return workCollection(results)
})
另外,正如建议的那样,如果订单无关紧要,请与Promise.all
一起使用,否则Promise Waterfall
方法也会如here所述。
答案 2 :(得分:1)
有很多事情:
return
来自then
回调的“承诺”结果,否则链条不会等待它q().then(function(){return true})
应该只是q(true)
reduce
回调已经提供了它。return true
并期待等待setTimeout
的任何事情。您需要promisify它(将其打包在new Q.Promise(…)
中),或者只使用Q.delay
。总而言之,您的代码应该如下所示:
var q = require('Q');
function workCollection(arr) {
return arr.reduce(function(promise, item, index) {
return promise.then(function(result) {
return Q.delay(result, 1000);
}).then(function(result) {
console.log('item', item, 'result', result, 'index', index);
return true;
});
}, q(true));
}
q().then(function(){
console.log('start');
return [1, 2, 3, 4, 5];
}).then(workCollection).then(function(result) {
console.log('done', result);
}, function(err){
console.error(err);
});
答案 3 :(得分:1)
你犯的错误是(除了不回复workCollection
承诺)setTimeout
没有被承诺,你可以修改它:
var q = require('Q');
var results = [1, 2, 3, 4, 5];
function delayedCall(i, r, idx){
return q.Promise(function(resolve, reject){
setTimeout(function(){
console.log('item', i, 'result', r, 'index', idx);
resolve(true);
}, 1000 * idx);
});
}
function workCollection(arr) {
return arr.reduce(function(promise, item, index) {
return promise.then(function(result) {
return delayedCall(item, result, index);
});
}, q(true));
}
q().then(function(){
console.log('start');
}).then(function(){
return workCollection(results)
}).then(function(){
console.log('done');
}).catch(function(err){
console.log(err);
});
fiddle demo,我使用Q.defer
代替Q.Promise
,但其余代码相同