How to make promise.all wait for nested promise.all?

痞子三分冷 提交于 2021-02-07 03:40:13

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!