问题
So I have a problem with JavaScript Promises. I'm using native implementation for the sake of reducing dependencies.
An illustrative example of what I need.
I need to retrieve lists of books, book authors and purchases. I also need an author profile for each of the authors. After I got all of that, I need to create a nice set of Authors with their books and purchase list for each of the books.
Lists and profiles are separate API JSON calls. The only dependency is that I need a list of authors to be able to get author profiles.
I've solved this with Promises. I use Promise.all to get 3 API JSON requests for: authors, books and purchases. I use yet another Promise.all to get all the profiles for each of the authors I get (I loop through the list, map urls for each profile and send a batch of requests in parallel).
I run the profile request batch as soon as I get the list of authors, thus in the "Then" handler of the author list promise.
Now, the problem:
To be sure that all promises, 3 lists and all profiles, will be done prior to my assembling of the library set, I would need to send a profile batch of requests when I'm done with all the lists, in the first Promise.all Then handler.
But: lists of books an purchases take much longer time than the list of authors and I don't want to wait for all of those to send a batch of profile requests, so I send it in the Then handler of the author-list promise so these start as soon as I have the info.
However, a nested Promise.all does not count towards its parent Promise.all Then handler so since my FinalFunction is in the Then of the top-level Promise.all, it may (and sometimes does) fire before the nested Promise.all has finished retrieving all author profiles.
I need to be able to start all of the Promise requests as soon as possible, but only the batch of author requests depends on one promise being complete to start, so I need to wait on that one. All other should start independently.
Pseudo code
Promise.all(
requestBooks().then(){},
requestAuthors().then(){
GenerateArrayOfAuthorUris();
// now send a promisifyed batch of per-author requests
Promise.all(
[array of author uris to run requests for]
)
.then(){
// If I run this here, I may not have upper-level requests done
runCalculationsPerAuthorForAllAuthorsBooksPurchasesReceived();
}
},
requestPurchases().then(){},
)
.then(){
// this will fire when 3 top requests are done, but won't wait for
// the nested Promise.all with per-author requests
runCalculationsPerAuthorForAllAuthorsBooksPurchasesReceived();
}
If I do it this way, I'm wasting precious time by waiting for requests I don't need to wait on just to start per-author requests:
Promise.all(
requestBooks().then(){},
requestAuthors().then(){
GenerateArrayOfAuthorUris();
},
requestPurchases().then(){},
)
.then(){
// now send a promisifyed batch of per-author requests
Promise.all(
[array of author uris to run requests for]
)
.then(){
// If I run this here, I may not have upper-level requests done
runCalculationsPerAuthorForAllAuthorsBooksPurchasesReceived();
}
}
Hopefully this clarifies what I need.
Thank you.
This is the code sample: https://jsbin.com/qizohasofa/edit?js,console
回答1:
As you were told in the comments, you didn't return
anything from your functions, so then
didn't know what inner promises to wait for.
function getJokeCategories() {
return Promise.all([
// ^^^^^^
pgetJSON("http://api.icndb.com/categories"),
pgetJSON("http://api.icndb.com/jokes/count").then(function(data) {
var jokesToGet = [];
for (var i=0; i<data; i++){
jokesToGet.push("http://api.icndb.com/jokes/"+i);
}
return Promise.all(jokesToGet.map(function(jk) {
// ^^^^^^
return pgetJSON(jk).then(function(joke) {
// ^^^^^^
console.log(jk + " just returned", joke);
return joke;
// ^^^^^^
});
})).then(function(jokes) {
console.log("All jokes returned. This does happen only when all jokes are retrieved.");
return {count:data, jokes:jokes};
// ^^^^^^
});
})
]);
}
getJokeCategories().then(function(result) {
console.log(result, "This does happen at the very end when joke count, joke categories and all jokes are returned.");
});
来源:https://stackoverflow.com/questions/36545464/how-to-make-promise-all-wait-for-nested-promise-all