首页 > 解决方案 > 如何使用 Promise.all 为 React 应用程序正确获取数据

问题描述

我正在开发一个 React 应用程序,我需要在组件安装时获取一些数据。由于我需要进行 3 次不同的调用,我认为最好使用 Promise.all 以并行方式进行。此处的代码工作得很好,它完全符合我的意图,但是,修改代码的人将其标记为错误,并带有消息“你没有在这里返回承诺。等待或承诺,但不是两者兼而有之”。我真的不明白他这话是什么意思。我只是一个初学者,他比我有更多的经验,所以我认为他是对的,这段代码是错误的,但我就是不知道为什么。

async componentDidMount() {   
    const start = Date.now();

    // TODO: BUG! you are not returning the promise here! Either await or promise but not both!
    const promises = [this.fetchReports({}), this.fetchEntities(), this.fetchCodePulseRange()];

    await Promise.all(promises);
    console.log("Data fetching time: ", Date.now() - start)
    this.setState({ inited: true });
  }  

  async fetchEntities() {
    const res = await insightService.fetchEntities(this.props.profile.organisationId);
    this.setState({ allEntities: res, entityType: 'product' });
  }

  async fetchReports(entities: { [key: string]: string }) {
    const res = await insightService.fetchInsights(reports, entities, this.props.profile.organisationId, JSON.stringify(entities));
    this.setState({ reportsWithData: res });
  }

  async fetchCodePulseRange() {
    const res = await insightService.fetchCodePulseRange(this.props.profile.organisationId);
    this.setState({ codePulseRange: res });
  }

标签: javascriptreactjstypescriptasynchronouspromise

解决方案


你最好的办法是问这个人他们的意思。我看不出你将承诺放在一个数组中然后awaiting有任何问题,Promise.all这样你就知道它们什么时候都已经实现了(或者其中一个被拒绝了)。Promise.all即使在函数中,审阅者也可能并不完全清楚它的作用和原因async(正是因为您指定的原因:开始操作,然后等待它们全部完成,允许它们并行运行) .

存在一个问题,即您的代码中没有任何内容可以处理或报告来自 fetch 操作的错误。这可能是他们试图在某种程度上间接表明的。Promise 的规则之一是:要么处理错误,要么将 Promise 链传播到将要发生的事情。React 不会处理来自 的承诺拒绝componentDidMount,因此您需要自己处理错误。

还将修改他的代码,以便您只进行一次状态更改而不是其中的四个:

componentDidMount() {   
    const start = Date.now();

    const promises = [this.fetchReports({}), this.fetchEntities(), this.fetchCodePulseRange()];
    Promise.all(promises)
    .then(([reportsWithData, allEntities, codePulseRange]) => {
        console.log("Data fetching time: ", Date.now() - start)
        this.setState({
            reportsWithData,
            allEntities,
            entityType: "product",
            codePulseRange,
            inited: true,
        });
    })
    .catch(error => {
        // ...handle/report error...
    });
    this.setState({ inited: true });
}  

fetchEntities() {
    return insightService.fetchEntities(this.props.profile.organisationId);
}

fetchReports(entities: { [key: string]: string }) {
    return insightService.fetchInsights(reports, entities, this.props.profile.organisationId, JSON.stringify(entities));
}

fetchCodePulseRange() {
    return insightService.fetchCodePulseRange(this.props.profile.organisationId);
}

但是如果你想保持增量更新(四个独立的状态更新),你可以这样做,只要确保处理错误,无论是在使用这些操作的componentDidMount地方还是在其他任何地方。fetchXyz例如,如果您不理会这些fetchXyz操作,则:

componentDidMount() {   
    const start = Date.now();

    const promises = [this.fetchReports({}), this.fetchEntities(), this.fetchCodePulseRange()];
    Promise.all(promises)
    .then(() => {
        console.log("Data fetching time: ", Date.now() - start)
        this.setState({ inited: true });
    })
    .catch(error => {
        // ...handle/report error...
    });
}  

或者

async componentDidMount() {   
    const start = Date.now();

    try {
        const promises = [this.fetchReports({}), this.fetchEntities(), this.fetchCodePulseRange()];
        await Promise.all(promises);
        console.log("Data fetching time: ", Date.now() - start)
        this.setState({ inited: true });
    } catch (error) {
        // ...handle/report error...
    }
}  

我不得不承认,我并不热衷于将承诺传递给不期望它们的事物(例如 React 代码调用componentDidMount),但这是一种相对较小的风格,我不会像在回馈。


推荐阅读