无法使用 Axios 和 array.map() 进行 async/await

jst*_*her 1 node.js async-await

我正在尝试构建一个映射给定数组的函数,然后对每个项目运行 axios 调用。完成后,我想返回映射的数组以在另一个函数中使用。

这是代码:

require('dotenv').config();
const axios = require('axios');
const consola = require('consola');

function getLeagues(listItems) {
  const today = new Date();
  const season = today.getMonth() >= 6 ? today.getFullYear() : today.getFullYear() - 1; // this gets the game ready for the new season every July 1st

  // we will end up directly returning listItems.map once the issue is solved
  const selectedLeagues = listItems.map(async (item) => {
    const countryName = item.country;
    const leagueName = item.league;

    try {
      const response = await axios({
        method: 'GET',
        url: `https://api-football-v1.p.rapidapi.com/v2/leagues/country/${countryName}/${season}`,
        headers: {
          'content-type': 'application/octet-stream',
          'x-rapidapi-host': 'api-football-v1.p.rapidapi.com',
          'x-rapidapi-key': process.env.FOOTY_API_KEY,
        },
      });

      const leagueData = response.data.api.leagues
        .filter((league) => league.name === leagueName)
        .map((data) => {
          return {
            leagueId: data.league_id,
            name: data.name,
            seasonStart: data.season_start,
            seasonEnd: data.season_end,
            country: data.country,
          };
        })
        .pop(); // we use pop() because filter() and map() return arrays and we don't want an array of 1 object, just that object

      consola.ready({
        // this displays all of the data as needed
        // this also runs after the below consola block
        message: `leagueData: ${JSON.stringify(leagueData, null, 2)}`,
        badge: true,
      });
      return leagueData;
    } catch (error) {
      throw new Error(error);
    }
  });

  consola.ready({
    // this displays an array with an empty object, not an array with above leagueData object
    // this also runs before the above consola block
    message: `selectedLeagues: ${JSON.stringify(selectedLeagues, null, 2)}`,
    badge: true,
  });

  return selectedLeagues;
}

module.exports = getLeagues;
Run Code Online (Sandbox Code Playgroud)

我不确定为什么在对象准备好selectedLeagues之前就返回数组。leagueData我认为 async/await 掌握了一切。相反,在我的控制台中,我得到:

selectedLeagues: [
  {}
]

leagueData: {
  "leagueId": 753,
  "name": "Liga 3",
  "seasonStart": "2019-07-19",
  "seasonEnd": "2020-05-16",
  "country": "Germany"
}
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?

cd3*_*d3k 7

您必须将您的listItems.mapPromise all 函数包装起来,因为map它本身与async.

// Now magically you can add async to your map function...
Promise.all(listItems.map(async item => {

  // Then put your try catch here so that it only wraps around
  // the results of the function you're awaiting...
  let response
  try {
    response = await axios()
  } catch (err) {
    return err;
  }

  // Anything else you want to do with the response...
  return response

})).then(results => {
  // All the resolved promises returned from the map function.
  console.log(results)

})
Run Code Online (Sandbox Code Playgroud)

当您await在异步函数中使用关键字时,其余代码将只等待等待函数的结果,try catch 部分是捕获您可能遇到的任何超出您控制范围的错误,这就是为什么您只尝试 catch 周围等待的功能。

如果您在 try catch 中包含太多代码,您将无法正确诊断和处理错误。

如果您愿意,您可以在整个代码周围放置一个 try catch,但问题是,每当您遇到任何小问题时,整个代码都会出错。

您也可以使用 for of 循环来完成此操作,这可能看起来更干净......

for await (let item of listItems) {
  // try catch await axios etc...
}
Run Code Online (Sandbox Code Playgroud)