首页 > 解决方案 > 并行执行 Promise 的最佳/最快方式?(反应)

问题描述

假设我需要获取数据来创建卡片。使用 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 中所做的事情?

标签: reactjsasync-awaitpromiseparallel-processingfetch

解决方案


如果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);

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


推荐阅读