网站搜索

javascript - 如何让 promise.all 等待嵌套的 promise.all?


所以我在使用 JavaScript Promises 时遇到了问题。我为了减少依赖,使用的是原生实现。

我所需要的一个说明性例子。

我需要获取书籍、书籍作者和购买记录的列表。我还需要每位作者的作者资料。在得到所有这些信息之后,我需要创建一套完整的作者及其书籍,并为每本书生成购买列表。

列表和简介是独立的 API JSON 调用。唯一的依赖是我需要一个作者列表才能获取作者简介。

我已经用 Promise 解决了这个问题。我使用 Promise.all 来获取 3 个 API 的 JSON 请求:作者、书籍和购买。我又使用了另一个 Promise.all 来获取我得到的每个作者的所有资料(我遍历列表,映射每个资料的 URL,并并行发送一批请求)。

我在得到作者名单后立即运行个人资料请求批处理,因此在作者名单承诺的“然后”处理程序中执行。

现在,问题是:

为了确保所有承诺、3 个列表和所有资料都会在我组装图书馆集合之前完成,我需要在完成所有列表后,在第一个 Promise.all 的 Then 处理程序中发送一批资料请求。

但是:书籍和购买清单比作者清单花的时间要长得多,而我不想等所有这些清单完成后才发送一批资料请求,所以我把它放在作者列表 promise 的 Then 处理函数中,这样一旦我有信息就可以开始。

然而,嵌套的 Promise.all 不算作其父级 Promise.all 的 Then 处理程序的一部分,因此由于我的 FinalFunction 位于顶级 Promise.all 的 Then 中,它可能(有时确实会)在嵌套的 Promise.all 完成获取所有作者资料之前就触发。

我需要尽可能快地启动所有的 Promise 请求,但只有那批作者请求依赖于一个 Promise 完成后才能开始,所以我需要等待那个完成。其他所有请求都应该独立启动。

伪代码

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();
}

如果我这样做,我就是在浪费宝贵的时间等待我不需要等待的请求,只是为了开始每位作者的请求:

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();
    }
}

希望这可以澄清我需要的内容。

谢谢你。

这是代码示例:https://jsbin.com/qizohasofa/edit?js,console

答案#1

正如评论中告诉你的,你没有从你的函数中 返回 任何东西,所以 then 不知道要等待哪些内部的 Promise。

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.");
});