无法使用Axios和array.map()进行异步/等待

时间:2020-03-15 05:41:54

标签: 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;

我不确定为什么在selectedLeagues对象尚未准备好之前就返回leagueData数组。我以为异步/等待可以容纳一切。相反,在控制台中,我得到:

selectedLeagues: [
  {}
]

leagueData: {
  "leagueId": 753,
  "name": "Liga 3",
  "seasonStart": "2019-07-19",
  "seasonEnd": "2020-05-16",
  "country": "Germany"
}

我在做什么错了?

3 个答案:

答案 0 :(得分:2)

不幸的是,listItems.mapmap不兼容,因此您必须将async包装在promise all函数中。

let results = Promise.all(listItems.map(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) {
    console.log(err)
  }
  // Anything else you want to do with the response...
}))

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

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

如果愿意,可以尝试遍历整个代码,但是问题是,只要有任何小问题,整个代码就会出错。

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

for await (let item of listItems) {
  // try catch await axios etc...
}

答案 1 :(得分:0)

您的.map()中发生的是异步的,而不是外部的。 .map()开始,但不会阻塞底部的consola.ready({

答案 2 :(得分:0)

您可以将异步与 Promise 结合使用,

    const arr = [1, 2, 3];
    
    const asyncRes = await Promise.all(arr.map(async (i) => {
        await sleep(10);
        return i + 1;
    }));

    console.log(asyncRes);
    // 2,3,4
相关问题