How to know when all Promises are Resolved in a dynamic “iterable” parameter?
我的问题是我不知道如何知道动态承诺数组何时解决了所有承诺。
这里是一个例子:
1 2 3 4 5 6 7 | 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*/}); |
我在这里有问题。
因此,我需要说的是:"嘿
请记住,这只是一个例子。我知道我可以将行
我真正的用例是这样的:
另一个困难的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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被调用时,我们需要调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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/
您可以制作一个简洁的递归函数来包装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | /** * 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!"); }); |
请记住,这仅涉及加法,并且仍然有些危险:您需要确保回调顺序如此,以便在运行
没有出路。您必须在数组中调用
如果要异步填充数组,则应获得对该数组的承诺,并使用
关于"美容示例",您将需要学习链接的魔力。正如我之前在评论中所说的那样,您必须
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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); }); |
这里没有动态增长的诺言数组,只是每个函数都针对其所做的(异步)结果返回诺言。
如果您可以兑现承诺或承诺的使用,而范围界定问题允许这样做,那么我认为您可以更简单地解决问题:有多少个承诺?
换句话说,您无需跟踪所有的承诺,只需计算它们即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
为了改善上述内容,请将其全部包装到meta-promise中(相当于Promise.all将返回的一组静态Promise)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 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将解析,然后函数完成。 (当然,您也需要处理catch语句。)
这将在通过Promise.then计划的所有代码完成时解决,而问题要求在所有Promise都解决后才能解决的问题。可以通过在promises的resolve语句之后添加调用来实现,但是如果使用3rd party库,那是不可能的,而且我认为它们在功能上是相同的。
这并非在所有情况下都有效,但是由于公认的答案是无法完成(动态的Promise),所以我认为尽管我写了它变得更加复杂(混乱),但这仍然有用。
@JeffBowman和@Bergi有正确的主意:递归等待和计数诺言。这是我在Coffeescript中的实现)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | 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." |