我的问题是我不知道如何知道动态promise数组何时解决了所有的promise。
这是一个例子:
var promiseArray = [];
promiseArray.push(new Promise(){/*blablabla*/});
promiseArray.push(new Promise(){/*blablabla*/});
Promise.all(promiseArray).then(function(){
// This will be executen when those 2 promises are solved.
});
promiseArray.push(new Promise(){/*blablabla*/});
我这里有问题。当前两个承诺被解决时,Promise.all
行为将被执行,但是,在这两个承诺被解决之前,第三个承诺被添加,而新的承诺将不被考虑。
所以,我需要的是说:“嘿Promise.all
,你有一个动态数组来检查”。我该怎么办?
请记住,这只是一个例子。我知道我可以将行Promise.all
移到最后一行,但实际上新的promise会在另一个promises被解决时动态添加,而新的promise也可以添加新的promise,因此,它是一个非常动态的数组。
我拥有的真实用例是这样的:
另一个难的例子:
var allPromises = [];
allPromises.push(new Promise(function(done, fail){
mongoDB.connect(function(error){
//Because mongoDB works with callbacks instead of promises
if(error)
fail();
else
ajax.get('/whatever').then(function(){
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
}));
} else {
ajax.get('/whatever/2').then(function(){
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
}));
}
});
}
}));
} else {
ajax.get('/whatever/2').then(function(){
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
}));
} else {
ajax.get('/whatever/2').then(function(){
if (somethingHappens) {
allPromises.push(new Promise(function(done, fail){ //This promise never will be take in account
// bla bla bla
}));
}
});
}
}));
}
});
}
});
});
}));
Promise.all(allPromises).then(function(){
// Soooo, all work is done!
mongodb.close()!
});
所以,现在,一个美容的例子。当调用最后一个(我们不知道哪个是最后一个)promise时,我们需要调用showAllTheInformation
函数。你是怎么做到的?:
var name = 'anonimus';
var date = 'we do not know';
function userClikOnLogIn() {
$http.get('/login/user/password').then(function(data){
if (data.logguedOk) {
$http.get('/checkIfIsAdmin').then(function(data){
if (data.yesHeIsAnAdmin) {
$http.get('/getTheNameOfTheUser').then(function(data){
if(data.userHasName) {
$http.get('/getCurrentDate').then(function(data){
currentDate = data.theNewCurrentDate;
});
}
});
}
});
}
});
}
function showAllTheInformation() {
alert('Hi ' + name + ' today is:' + date);
}
这里有更多上下文的另一个例子: https://jsfiddle.net/f0a1s79o/2/
答案 0 :(得分:11)
您可以创建一个简洁的小递归函数来包装Promise.all
以处理添加到原始承诺:
/**
* Returns a Promise that resolves to an array of inputs, like Promise.all.
*
* If additional unresolved promises are added to the passed-in iterable or
* array, the returned Promise will additionally wait for those, as long as
* they are added before the final promise in the iterable can resolve.
*/
function iterablePromise(iterable) {
return Promise.all(iterable).then(function(resolvedIterable) {
if (iterable.length != resolvedIterable.length) {
// The list of promises or values changed. Return a new Promise.
// The original promise won't resolve until the new one does.
return iterablePromise(iterable);
}
// The list of promises or values stayed the same.
// Return results immediately.
return resolvedIterable;
});
}
/* Test harness below */
function timeoutPromise(string, timeoutMs) {
console.log("Promise created: " + string + " - " + timeoutMs + "ms");
return new Promise(function(resolve, reject) {
window.setTimeout(function() {
console.log("Promise resolved: " + string + " - " + timeoutMs + "ms");
resolve();
}, timeoutMs);
});
}
var list = [timeoutPromise('original', 1000)];
timeoutPromise('list adder', 200).then(function() {
list.push(timeoutPromise('newly created promise', 2000));
});
iterablePromise(list).then(function() { console.log("All done!"); });

请记住,这仅仅包括添加内容,并且它仍然有点危险:您需要确保回调订单是这样的,即飞行中的任何承诺将自己添加到列表之前可以调用Promises.all
回调。
答案 1 :(得分:2)
没有出路。在调用Promise.all
之前,你必须将所有的promises放在数组中。在您提供的示例中,这就像将最后一行移到顶部一样简单。
如果您异步填充数组,则应该获得该数组的承诺,并使用.then(Promise.all.bind(Promise))
。如果你不知道什么时候停止添加承诺,那么这是不可能的,因为它们可能永远都不会被解决。
关于您的“美容示例”,您需要了解magic of chaining。正如我在评论中所说的那样,你必须return
来自你正在做异步的每个函数的承诺。实际上,只需添加缺少的return
s:
function userClikOnLogIn() {
return $http.get('/login/user/password').then(function(data){
// ^^^^^^
if (data.logguedOk) {
return $http.get('/checkIfIsAdmin').then(function(data){
// ^^^^^^
if (data.yesHeIsAnAdmin) {
return $http.get('/getTheNameOfTheUser').then(function(data){
// ^^^^^^
if(data.userHasName) {
return $http.get('/getCurrentDate').then(function(data){
// ^^^^^^
currentDate = data.theNewCurrentDate;
});
}
});
}
});
}
});
}
userClikOnLogIn().then(function showAllTheInformation() {
// ^^^^^ now you can chain onto it!
alert('Hi ' + name + ' today is:' + date);
});
这里没有任何承诺数组会动态增长,只是每个函数都返回它所做事物的(异步)结果的承诺。
答案 2 :(得分:2)
我知道我在这里参加聚会迟到了。但是,对于那些感到难过却找不到快速答案的人,这是一种肮脏的方法(稍后解释),而无需重新架构,前提是您确定在完成所有任务后不会添加新的承诺现有的诺言。
var promiseArray = [], completedPromises = [];
promiseArray.push(new Promise(){/*blablabla1*/});
promiseArray.push(new Promise(){/*blablabla2*/});
while(completedPromises.length != promiseArray.length) completedPromises = await Promise.all(promiseArray);
代码中的其他位置(在完成所有先前的承诺之前:
promiseArray.push(new Promise(){/*blablabla3*/});
希望这对某人有帮助。经过多年的免费下载,我才创建了一个堆栈溢出帐户:)
答案 3 :(得分:1)
如果您可以检查承诺或其使用情况,并确定范围问题,那么我认为您可以更简单地解决问题:承诺有多少承诺?
换句话说,你不需要跟踪所有的承诺,只需计算它们。
var outstanding = 0;
var p1 = new Promise(){/*blablabla*/};
var p2 = new Promise(){/*blablabla*/};
++outstanding;
p1.then( (data) => { ...
if (0 >= --outstanding)
// All resolved!
}
// dynamic set of promises, so later we decide to add another:
var p3 = new Promise(){/*blablabla*/};
++outstanding;
p3.then( ... ); // as above
为了改进上述内容,将其全部包含在元承诺中(与Promise.all为一组静态承诺返回的承诺相等)...
// Create a promise that tracks completion of a dynamic set of instrumented promises.
getCompletionP() {
let rslv = null;
const p = new Promise(
function(resolve, reject) {
rslv = resolve;
} );
p.resolve = rslv;
assert( p.resolve );
p.scheduled = 0;
p.onSchedule = function() { ++this.scheduled; };
p.onComplete = function() { if (0 >= --this.scheduled) this.resolve(); };
return p;
}
现在在每次调用then()之前调用cp.onSchedule(),然后在每个then()结束时调用cp.onComplete,并且cp将在所有promise之后解析,然后函数完成。 (当然,你也需要处理catch语句。)
当通过Promise.then调用完成的所有代码完成时,这将解决,而问题要求解决所有promises时解决的问题。这可以通过在promises的resolve语句之后添加调用来实现,但是如果使用第三方库则这是不可能的,并且我认为它们在功能上是相同的。
这不适用于所有情况,但由于接受的答案是它(动态的承诺集)无法完成,我认为这仍然有用虽然它变得更复杂(凌乱),因为我写的它出来了!
答案 4 :(得分:0)
@JeffBowman和@Bergi有正确的想法:递归等待和计数承诺。这是我在Coffeescript中的实现)
Promise = require 'bluebird'
class DynamicPromiseCollection
promises = []
add:(p)->
promises.push p
wait_for_all:->
#
# Wait for all current promises, then check for new promises...
# ...if there are new promises, then keep waiting ( recursively ).
#
# Resolve only when all promises are done, and there are no new promises.
#
make_promise = ->
num_before = promises.length
p = Promise.all(promises).then ->
num_after = promises.length
if num_after > num_before
return make_promise() # recursive -- wait again
else
return true # all done now
p = make_promise()
return p
#
# let's test this...
#
promises = new DynamicPromiseCollection()
#
# pretend to get remote data
#
get_remote_data = ->
new Promise (resolve,reject)->
setTimeout ->
resolve "data"
,500
#
# get data, wait, then get more data...
#
promises.add get_remote_data().then (data)->
console.log "got " + data
promises.add get_remote_data().then (data)->
console.log "got " + data
#
# this should wait for both data
#
promises.wait_for_all().then ->
console.log "...and wait_for_all is done."