React Promise异步任务顺序不正确

Koa*_*la7 5 javascript promise reactjs react-hooks use-effect

我正在使用 Promise 进行多次调用。

我要获取的 API 端点是:

  1. https://www.api-football.com/demo/v2/statistics/357/5/2019-08-30
  2. https://www.api-football.com/demo/v2/statistics/357/5/2019-09-30
  3. https://www.api-football.com/demo/v2/statistics/357/5/2019-10-30

看代码

export function getTeamsStats(league, team, type) {
  return function(dispatch) {

    const url = "https://www.api-football.com/demo/v2/statistics";
    let dates = ["2019-08-30", "2019-09-30", "2019-10-30"];
    const getAllData = (dates, i) => {
      return Promise.allSettled(dates.map(x => url + '/' + 357 + '/' + 5 + '/' + x).map(fetchData));
    }

    const fetchData = (URL) => {
      return axios
        .get(URL)
        .then(res => {
          const {
            matchsPlayed: { total: teamsTotalMatchsPlayed},
          } = res.data.api.statistics.matchs;

          const matchsPlayed = teamsTotalMatchsPlayed;

          dispatch(receivedTeamsStat(matchsPlayed, type));
        })
        .catch(e => {
          console.log(e);
        });
    }

    getAllData(dates).then(resp=>{console.log(resp)}).catch(e=>{console.log(e)})

  }
}
Run Code Online (Sandbox Code Playgroud)

然后在我的组件中,我将这个特定球队(在本例中为圣保罗)从初始日期30-8-201930-10-2019 进行的比赛放入一个数组中

    const [dataHomeTeam, setDataHomeTeam] = useState([]);

      useEffect(() => {
    
         if (!team.matchsPlayed) {
           return ;
         }
    
         setDataHomeTeam(prev =>
           prev.concat([
             {
               matches: team.matchsPlayed,
             }
           ])
         );
    
       },[team.matchsPlayed]);

console.log('Data Array', dataHomeTeam);
Run Code Online (Sandbox Code Playgroud)

问题是,通常在页面的第一次渲染中,我的匹配顺序是正确的,从30-8-2019 到 30-10-2019

查看控制台日志图像

正确的顺序

但有时不是,请看这里

在此处输入图片说明

所以问题是,我如何确保 Promise 以正确的请求顺序返回给我?

我正在使用Promise.allSettled,多个不相互依赖才能成功完成的异步任务,但顺序并不总是正确的。

zhu*_*ber 5

这应该通过Promise.all解决,因为如文档中所述

返回值将按照传递的 Promise 顺序排列,而不管完成顺序。

您遇到的问题是,您通过dispatch根据完成情况调用每个承诺来设置您的状态,并且由于承诺可以在任何给定时间完成(例如,第三个请求可以先完成,因为它们是同时发送的),dispatch将被调用和您的状态管理会将其设置为第一响应(这就是您“有时”会出现此类行为的原因,因为这取决于网络哪个先完成)。

这意味着要么您应该更改dispatch接收已完成承诺的数组,要么在完成后dispatch一一调用,如下面的代码所示 - 全部解析并按顺序分派:

export function getTeamsStats(league, team, type) {
    return function (dispatch) {
    const url = "https://www.api-football.com/demo/v2/statistics";
    let dates = ["2019-08-30", "2019-09-30", "2019-10-30"];
    const getAllData = (dates, i) => {
        return Promise.all(dates.map(x => url + '/' + 357 + '/' + 5 + '/' + x).map(fetchData));
    }

    const fetchData = (URL) => {
        return axios
            .get(URL)
            .then(res => {
                const {
                    matchsPlayed: { total: teamsTotalMatchsPlayed },
                } = res.data.api.statistics.matchs;

                return teamsTotalMatchsPlayed;
            })
            .catch(e => {
                console.log(e);
            });
    }

    getAllData(dates).then(resp => {
        console.log(resp)

        // 'resp' here are all 'teamsTotalMatchsPlayed' in correct order (here I mean order of call, not promise completion)
        // so just dispatch them in order
        resp.map(matchsPlayed => receivedTeamsStat(matchsPlayed, type));            
    }).catch(e => { 
        console.log(e) 
    })

   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,我可能犯了一些语法错误,但您明白了。