【问题标题】:Best/Quickest way to execute Promises in-parallel? (React)并行执行 Promise 的最佳/最快方式? (反应)
【发布时间】:2021-12-19 22:29:23
【问题描述】:

假设我需要获取数据来创建卡片。使用 Promise 获取这些数据的最快方法是什么?这是我目前的做法:

  async function getCards() {

    const promises = []
    for (let i = 0; i < 10; i++) {
      promises.push(getCard(i))
    }

    const cards = await Promise.allSettled(promises)
    setCards(cards)
  }

  async function getCard(i) {
    const property1 = await getProperty1(i)
    const property2 = await getProperty2(i)
    const property3 = await getProperty3(i)

    const card = <div>
      <div>Property 1: {property1}</div>
      <div>Property 2: {property2}</div>
      <div>Property 3: {property3}</div>
    </div>

    return card
  }

出于我的目的,我不需要 Promise.allSettled,因为我不需要等待所有 10 张卡都完成等待(我可能只是创建一个组件),我可以在它们完成时渲染每张卡。但我仍然希望它尽可能快地并行/执行。我还有哪些其他选择?有没有更好的方法来处理我在 getCard 中所做的事情?

【问题讨论】:

  • 这里有实际的异步操作吗? getProperty1() 是做什么的?如果不是,则不会有并行性,因为同步代码在单个线程中运行(除非您使用 webWorkers)。如果您有实际的异步操作,请向我们展示实际的异步代码。尝试使用Promise.allSettled() 不会带来任何好处,除非这些承诺正在监视实际的异步代码。
  • 另外,promise 不会“执行”。 Promise 只是一些其他操作(通常是异步的)使用的通知机制。它是另一个执行的操作,然后在完成时告诉 Promise,然后 Promise 通知其他代码完成。虽然这主要是命名法,但对于全面了解什么是承诺以及如何使用它也很重要。
  • getProperty 从 API 中获取一个值,其中 i 是 ID
  • 然后向我们展示该代码
  • 这是我写的伪代码。假设 getProperty 调用 fetch 或类似的东西

标签: reactjs async-await promise parallel-processing fetch


【解决方案1】:

如果getPropertyN() 确实是一个异步操作(例如网络请求),那么getCards() 将并行运行您的for 循环中的所有调用,这样它们都在同时进行中与串行运行相比,它通常会减少端到端时间。

还有其他一些因素在起作用,例如接收主机在一次收到一堆请求时会做什么。如果它一次只处理一个,那么您可能不会获得很多。但是,如果主机具有任何并行性,那么通过同时运行多个请求,您肯定会看到加速。

请注意,您的 getCard(i) 实现正在序列化对 getProperty1()getProperty2()getProperty3() 的三个调用,这也许也可以与类似的东西并行完成:

const [property1, property2, property3] = await Promise.all([
    getProperty1(i),
    getProperty2(i),
    getProperty3(i)
]);

而不是这个:

const property1 = await getProperty1(i)
const property2 = await getProperty2(i)
const property3 = await getProperty3(i)

要记住的另一件事是浏览器(例如fetch() 调用)只会向同一主机发出 N 个同时请求(其中 N 约为 6)。一旦超过了对同一主机同时进行的所有请求的数量,浏览器会将其余请求排队,直到前一个请求完成。它的实现方式不会减慢处理超过最大请求的速度,但是在浏览器的限制之后您不会获得更多的并行性。如果您从不同的 Javascript 环境(例如 nodejs)运行此代码,则该限制将不适用,因为这是特定于浏览器的事情。

注意,实现并行性的关键是同时启动多个正在进行的请求。没有要求您在对任何结果进行操作之前使用Promise.allSettled(),除非您需要在处理结果之前按顺序获取所有结果。

如果结果可以在完成时单独处理并且可以按任何顺序处理,您也可以这样编写代码而不使用Promise.allSettled(),例如:

 getProperty(1).then(processResult).catch(processErr);
 getProperty(2).then(processResult).catch(processErr);
 getProperty(3).then(processResult).catch(processErr);

注意:我也没有在您的代码中看到任何错误处理。任何外部网络请求都可能失败,您必须有一些处理程序来处理被拒绝的承诺。

【讨论】:

  • 那么 Promise.all 本质上等同于在 for 循环中运行请求吗?我在其他地方读到了 for 循环中等待的地方是串行运行而不是并行运行
  • @greentriangles1 - Promise.all() 不运行任何东西。您自己的代码首先调用函数,然后将一组承诺传递给Promise.all()。所有promise.all() 所做的就是监控这些承诺的完成情况。是的,awaits 在循环中是串行运行的,但这与Promise.all() 无关。
猜你喜欢
  • 2015-09-21
  • 1970-01-01
  • 2014-10-01
  • 2018-07-24
  • 2012-01-29
  • 1970-01-01
  • 1970-01-01
  • 2016-04-03
  • 1970-01-01
相关资源
最近更新 更多