在解析到下一个之前减少所有 JS Promises
Reducing all JS Promises before resolving to next then
我似乎找不到解决此问题的正确方法。我有一堆 thenables 的承诺,在其中一个解析器中,我想暂停并在数组上做一系列工作(使用承诺),我不希望在一系列承诺完成之前真正解决这个问题完全的。这个例子似乎让我非常接近,但我想我可能已经创建了一个反模式。
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
非常感谢您的建议。请在投票前发表评论。
您可以使用 promise.all()
实现此目的。只需将您的每个数组承诺推入一个数组(通常名称为 deferred
)然后 return promise.all(deferred)
此处的文档:https://github.com/kriskowal/q/wiki/API-Reference#promise-for-array-methods
更新
我创建了一个使用 deferred
的 fiddle,而不是编辑您的 fiddle,在这种情况下您应该使用它。 https://jsfiddle.net/twler/aujqcmhv/1/
希望它能澄清一些有关 promise 对象的信息,因为它们可能会造成混淆。
我认为您会在 start
之后立即获得 done
,因为您当时没有返回 workCollection(results)
的结果,因此它会立即通过 undefined
得到解决。试试这个
.then(function(){
return workCollection(results)
})
此外,如建议的那样,如果顺序无关紧要,请使用 Promise.all
否则您的 Promise Waterfall
方法也如 here 所述是好的。
有很多事情:
- 如前所述,您需要
return
来自 then
回调的 `` 的(承诺)结果,否则链不会等待它
q().then(function(){return true})
应该只是 q(true)
- IIFE 没用。如果您需要任何闭包作用域,
reduce
回调已经提供了它。
- 您不能
return true
并期望任何事情都在等待 setTimeout
。您需要 promisify it (wrap it in a new Q.Promise(…)
), or just use 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);
});
你犯的错误是(除了没有返回 workCollection
promise)setTimeout
没有被 promisified,你可以像这样修复它:
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
但其余代码是相同的
我似乎找不到解决此问题的正确方法。我有一堆 thenables 的承诺,在其中一个解析器中,我想暂停并在数组上做一系列工作(使用承诺),我不希望在一系列承诺完成之前真正解决这个问题完全的。这个例子似乎让我非常接近,但我想我可能已经创建了一个反模式。
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
非常感谢您的建议。请在投票前发表评论。
您可以使用 promise.all()
实现此目的。只需将您的每个数组承诺推入一个数组(通常名称为 deferred
)然后 return promise.all(deferred)
此处的文档:https://github.com/kriskowal/q/wiki/API-Reference#promise-for-array-methods
更新
我创建了一个使用 deferred
的 fiddle,而不是编辑您的 fiddle,在这种情况下您应该使用它。 https://jsfiddle.net/twler/aujqcmhv/1/
希望它能澄清一些有关 promise 对象的信息,因为它们可能会造成混淆。
我认为您会在 start
之后立即获得 done
,因为您当时没有返回 workCollection(results)
的结果,因此它会立即通过 undefined
得到解决。试试这个
.then(function(){
return workCollection(results)
})
此外,如建议的那样,如果顺序无关紧要,请使用 Promise.all
否则您的 Promise Waterfall
方法也如 here 所述是好的。
有很多事情:
- 如前所述,您需要
return
来自then
回调的 `` 的(承诺)结果,否则链不会等待它 q().then(function(){return true})
应该只是q(true)
- IIFE 没用。如果您需要任何闭包作用域,
reduce
回调已经提供了它。 - 您不能
return true
并期望任何事情都在等待setTimeout
。您需要 promisify it (wrap it in anew Q.Promise(…)
), or just useQ.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);
});
你犯的错误是(除了没有返回 workCollection
promise)setTimeout
没有被 promisified,你可以像这样修复它:
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
但其余代码是相同的