插件窝 干货文章 Promiseall( ) 困境:什么时候有帮助,什么时候有害

Promiseall( ) 困境:什么时候有帮助,什么时候有害

promise 异步 请求 strong 637    来源:    2024-10-20

在现代 javascript 开发中,处理异步操作是一项常见任务。无论是发出 api 请求、查询数据库还是读取文件,使用异步代码几乎是不可避免的。开发人员遇到的常见工具之一是 promise.all()。然而,我们中的许多人,包括我自己,可能会陷入尝试使用 promise.all() 的陷阱,只是因为它在那里,而没有真正理解它是否是我们特定用例的最佳解决方案。

1. 跟随 promise.all() 潮流

作为开发人员,很容易遇到新功能或工具,并认为它们应该在任何地方实现。我发现自己在 promise.all() 中处于这种情况。在阅读了它如何并行运行多个 promise 并等待所有 promise 完成后再继续后,我渴望将其集成到我的代码中。在没有完全理解是否有必要的情况下,我就跟风并尽可能地应用它。

很容易认为,既然它是一个强大的工具,它一定比更简单的替代品更好。但我很快意识到,盲目应用 promise.all() 而不考虑上下文并不总是能带来最高效或可读的代码。

2. 异步 javascript 基础知识

在我们深入探讨 promise.all() 何时有用之前,让我们首先看看异步函数在 javascript 中是如何工作的。当您编写异步函数并使用等待时,javascript 允许该操作发生,而不会阻塞其余代码。这意味着您可以启动一项操作,然后在等待结果的同时继续执行其他操作。

但是,如果您不小心,当操作可以独立运行时,您最终可能会导致操作不必要地相互依赖。我发现自己处于 promise.all() 的这种情况,认为并行运行所有异步函数总是一个好主意。

示例:异步函数的顺序执行

const fetchdata = async () => {
  const data1 = await getchart();   // request #1
  const data2 = await getdetails(); // request #2
};

即使在代码中 data1 和 data2 被依次获取,浏览器仍然异步且几乎同时发起这两个请求。事实上,当我检查“网络”选项卡时,我看到两个请求大约在同一时间开始。这让我意识到 javascript 已经可以并行处理事情了,而 promise.all() 并不是必需的。

3.什么时候应该使用promise.all()?

尽管我最初急于在任何地方使用 promise.all(),但在某些情况下它确实会大放异彩。当您需要等待多个异步操作完成才能继续操作时,它特别有用。

为什么使用 promise.all()?

  1. 等待所有 promise:如果多个异步任务的结果相互依赖,或者需要所有异步任务完成才能继续,promise.all() 是理想的选择。
  2. 错误处理:promise.all() 快速失败——这意味着如果任何 promise 失败,整个操作都会被拒绝。当您想要确保一切都成功或者没有任何进展时,这会很有用。
  3. 组合结果:如果您需要一次获得所有 promise 的结果(例如,将用户数据与购买历史记录相结合),promise.all() 是完美的解决方案。

示例:使用 promise.all()

const fetchdata = async () => {
  const [data1, data2] = await promise.all([getchart(), getdetails()]);
  console.log('both requests completed'); // this runs only when both requests finish
};

在此示例中,getchart() 和 getdetails() 并行运行,并且该函数会等到两者都完成后再继续。 promise.all() 在这种两个请求相关且需要一起完成的情况下非常完美。

4. 为什么我不需要 promise.all()

应用 promise.all() 几次后,我开始注意到它并不总是能让我的代码变得更好。事实上,我把事情过于复杂化了。我有两个独立的 api 请求 — getchart() 和 getdetails() — 每个请求都有自己的加载微调器和结果,但我不必要地将它们捆绑在一起。

通过使用 promise.all(),我强制代码在处理任一结果之前等待两个请求完成,即使这些请求是独立的并且不相互依赖。在这种情况下,promise.all() 只会增加复杂性,而没有任何实际好处。

5. 当 promise.all() 可能有点大材小用时

有时,promise.all() 有点矫枉过正。如果您的异步函数是独立的,这意味着一个函数不依赖另一个函数来完成,则无需将它们捆绑在一起。它们可以很好地并行运行,而无需相互等待,并且您可以独立处理它们的结果。当我看到 javascript 已经可以高效地处理异步任务而无需将所有内容组合在一起时,我意识到了这一点。

何时避免 promise.all()

  1. 独立的异步函数:如果您的请求彼此不依赖,它们可以在不同的时间完成,并且您可以单独处理它们的结果。无需等待所有人一起完成。
  2. 单独的加载状态:就我而言,我为每个请求都有单独的加载旋转器,但我不必要地通过等待这两个请求来阻止一切。最好单独处理每个请求,并在每个请求完成后立即更新 ui。

示例:没有 promise.all() 的独立请求

useeffect(() => {
  getchart();   // trigger first async request
  getdetails(); // trigger second async request
}, []);

在此设置中,两个请求并行运行,无需 promise.all()。您可以显示单独的加载状态并独立处理每个结果,这正是我的项目所需要的。

6. 使用或避免 promise.all() 的现实场景

让我们看看这些概念如何应用于现实场景。

场景1:获取相关数据(使用promise.all())

假设您正在构建一个仪表板,您需要在其中一起显示用户信息和用户购买历史记录。在这种情况下,您需要等待两条信息加载后再渲染 ui。在这里,promise.all() 是正确的选择:

const fetchdata = async () => {
  const [userinfo, purchasehistory] = await promise.all([
    fetchuserinfo(),
    fetchuserpurchasehistory()
  ]);
  console.log('both user info and purchase history loaded');
};

场景 2:独立 api 调用(避免 promise.all())

现在,假设您正在为仪表板获取图表数据和表格数据,并且这两条信息是相互独立的。您可能希望为图表显示一个微调器,并为表格显示一个单独的微调器。在这种情况下,无需等待两个请求一起完成:

useEffect(() => {
  getChart();   // Fire chart request
  getDetails(); // Fire table request
}, []);

这两个请求都是独立的,您可以单独处理每个请求,并在每个请求完成后立即更新 ui。这里不需要 promise.all()。

结论:不要随波逐流

promise.all() 是一个强大的工具,但它并不总是最好的解决方案。我一开始就跟上了潮流,认为在任何地方使用它都会让我的代码变得更好。然而,我很快了解到,在异步函数是独立的并且有自己的加载状态的情况下,promise.all() 实际上会让事情变得更加复杂。

要点:

  • 当您需要等待多个 promise 解决后再继续操作时,请使用 promise.all()。
  • 当异步任务是独立的时,请避免使用 promise.all(),并且您可以单独处理它们,而无需不必要的等待。

最终,重要的是要了解何时以及为何使用 promise.all() 这样的功能,而不是仅仅假设它总是有益的。退后一步并重新评估我的用例后,我发现坚持使用独立的异步调用是正确的方法。