何时使用 promise.all()?

IT技术 javascript design-patterns promise
2021-03-22 18:31:06

这更像是一个概念性问题。我了解 Promise 设计模式,但找不到可靠的来源来回答我的以下问题promise.all()

什么是(是)使用的正确场景 promise.all()

或者

是否有任何最佳实践可供使用promise.all()只有当所有的Promise对象都是相同或相似的类型时才应该理想地使用它吗?

我唯一能想到的就是:

  • promise.all()如果您只想所有Promise对象都解决并拒绝甚至一个拒绝时才解决Promise,请使用
6个回答

我不确定是否有人真的对何时使用Promise.all()(以及何时不使用)给出了最通用的解释

什么是使用 promise.all() 的正确场景

Promise.all()当您有多个Promise并且您的代码想知道这些Promise所代表的所有操作何时成功完成时,这非常有用。各个异步操作是什么并不重要。如果它们是异步的,由 promise 表示,并且您的代码想知道它们何时都成功完成,那么Promise.all()构建就是为了做到这一点。

例如,假设您需要从三个单独的远程 API 调用中收集信息,并且当您获得所有三个 API 调用的结果时,您就需要使用所有三个结果运行一些进一步的代码。这种情况将是完美的Promise.all()你可以这样:

Promise.all([apiRequest(...), apiRequest(...), apiRequest(...)]).then(function(results) {
    // API results in the results array here
    // processing can continue using the results of all three API requests
}, function(err) {
    // an error occurred, process the error here
});

Promise.all()可能最常用于类似类型的请求(如上例所示),但没有理由需要它。如果你有一个不同的情况,你需要发出一个远程 API 请求,读取一个本地文件并读取一个本地温度探测器,然后当你有来自所有三个异步操作的数据时,你想要对所有数据进行一些处理三,你会再次使用Promise.all()

Promise.all([apiRequest(...), fs.promises.readFile(...), readTemperature(...)]).then(function(results) {
    // all results in the results array here
    // processing can continue using the results of all three async operations
}, function(err) {
    // an error occurred, process the error here
});

另一方面,如果您不需要在它们之间进行协调并且可以单独处理每个异步操作,那么您不需要Promise.all(). 您可以使用自己的.then()处理程序触发每个单独的异步操作,并且不需要它们之间的协调。

此外Promise.all()还有所谓的“快速失败”实现。它返回一个主Promise,一旦您通过它的第一个Promise被拒绝,它就会拒绝,或者当所有Promise都已解决时它将解决。因此,使用Promise.all()这种类型的实现需要适合您的情况。在其他情况下,您想要运行多个异步操作并且您需要所有结果,即使其中一些失败。 Promise.all()不会直接为你做那件事。相反,您可能会Promise.settle()在这种情况下使用类似的东西你可以看到这里的实现.settle()这使您可以访问所有结果,即使有些结果失败。当您预计某些操作可能会失败并且您有一项有用的任务需要使用任何成功操作的结果时,或者您想检查所有未能基于此做出决策的操作的失败原因时,这尤其有用。

是否有使用 promise.all() 的最佳实践?只有当所有的Promise对象都是相同或相似的类型时才应该理想地使用它吗?

如上所述,单独的异步操作是什么或者它们是否是相同的类型并不重要。重要的是您的代码是否需要协调它们并知道它们何时全部成功。


列出一些您不会使用的情况也很有Promise.all()

  1. 当您只有一个异步操作时。只需一个操作,您就可以.then()在一个 promise 上使用处理程序,而没有理由使用Promise.all().
  2. 当您不需要在多个异步操作之间进行协调时。
  3. 当快速失败实施不合适时。如果您需要所有结果,即使有些结果失败,那么Promise.all()它本身也不会这样做。你可能想要类似的东西Promise.allSettled()
  4. 如果您的异步操作未全部返回Promise,Promise.all()则无法跟踪未通过Promise管理的异步操作。
这句话让我明白了一切。如果要执行传递从多个 ajax 调用获得的参数的函数。然后Promise一切都是正确的做法。
2021-05-06 18:31:06
maaan 这个答案太棒了!你教什么的?因为我很乐意参加!
2021-05-13 18:31:06

Promise.all用于等待多个 Promise 并行(同时)解决。当所有输入 Promise 都已解决时,它会返回一个已解决的 Promise:

// p1, p2, p3 are Promises
Promise.all([p1, p2, p3])
  .then(([p1Result, p2Result, p3Result]) => {
    // This function is called when p1, p2 and p3 have all resolved.
    // The arguments are the resolved values.
  })

如果任何输入 Promise 被拒绝,则返回的 PromisePromise.all也会被拒绝。

一个常见的场景是等待多个 API 请求完成,以便您可以组合它们的结果:

 const contentPromise = requestUser();
 const commentsPromise = requestComments();

 const combinedContent = Promise.all([contentPromise, commentsPromise])
   .then(([content, comments]) => {
     // content and comments have both finished loading.
   })

您可以Promise.allPromise实例一起使用

很难回答这些问题,因为当人们使用语言功能的可用 API 时,这些问题往往会自行回答。基本上,只要您避免使用 Promise 的反模式,就可以以任何适合您的用例的方式使用 Promise

什么是使用 promise.all() 的正确场景

操作取决于多个Promise的成功解决的任何情况。

是否有使用 promise.all() 的最佳实践?只有当所有的Promise对象都是相同或相似的类型时才应该理想地使用它吗?

一般来说,没有和没有。

我用promise.all()的时候我必须做一些要求我的API,我不希望加载应用程序的所有数据请求之前显示的东西,所以我推迟执行流程,直到我有我需要的所有数据。

例子:

我想要做什么 我想在我的应用程序中显示包含用户电子邮件和每个用户的产品名称的表格之前加载我的应用程序及其产品的用户(假设您必须执行多个请求)。

接下来我要做的是将请求发送到我的 API 创建Promise并使用promise.all()

加载所有数据后我要做的事情一旦数据到达我的应用程序,我就可以执行 的回调,promises.all()然后让用户看到该表。

我希望它可以帮助您了解在哪种情况下使用有意义 promises.all()

正如@joews 所提到的,可能Promise.all应该明确指出的重要特性之一它使您的异步代码更快

这使它适用于任何包含独立调用的代码(我们希望在其余代码继续之前返回/完成),但尤其是当我们进行前端调用并希望用户体验尽可能流畅时。

async function waitSecond() {
  return new Promise((res, rej) => {
    setTimeout(res, 1000);
  });
}

function runSeries() {
  console.time('series');
  waitSecond().then(() => {
    waitSecond().then(() => {
      waitSecond().then(() => {
        console.timeEnd('series');
      });
    });
  });
}

function runParallel() {
  console.time('parallel');
  Promise.all([
    waitSecond(),
    waitSecond(),
    waitSecond(),
  ]).then(() => {
    console.timeEnd('parallel');
  });
}

runSeries();
runParallel();