如何解决在 promise 链中调用 axios get 请求的多个函数?

How to resolve multiple functions that invoke axios get requests within a promise chain?

基本上我正在尝试编写一个函数,该函数将 return 球队得分列表,球队名称位于他们的得分旁边。但是,因为检索团队名称的函数 return 是一个未决的承诺,所以我永远无法在控制台中看到这些名称。

我如何解决这些承诺,以便在承诺链的下一个 .then 块中,我可以看到分数两侧的球队名称,而不是 [object Promise]

[在此图片中,您可以看到变量中存储的两个 fetchTeamNames 函数的完整函数][1]

fetchFullTimeHeadToHeadScore函数是父函数:

function fetchFullTimeHeadToHeadScore(homeTeamId, awayTeamId) {
  return axios
    .get(
      `https://soccer.sportmonks.com/api/v2.0/head2head/${homeTeamId}/${awayTeamId}?api_token=${apiKey}`
    )
    .then((res) => {
      const homeSide = fetchTeamName(homeTeamId).then((res) => {
        return res;
      });
      const awaySide = fetchTeamName(awayTeamId).then((res) => {
        return res;
      });

      return [homeSide, res.data.data, awaySide];
    })
    .then((data) => {
      return data[1].map((obj) => {
        return data[0] + " " + obj.scores.ft_score + " " + data[2];
      });
    })
    .then((scores) => {
      scores.length = 10;
      return scores;
    })
    .catch((err) => {
      console.log(err);
    });
}

...调用 fetchTeamName 函数:

function fetchTeamName(teamId) {
  return axios
    .get(
      `https://soccer.sportmonks.com/api/v2.0/teams/${teamId}?api_token=${apiKey}`
    )
    .then((res) => {
      return res.data.data.name;
    });
}

...我希望在控制台中能够看到团队的名称,但目前仅输出 [object Promise]:

- Expected  - 10
+ Received  + 10

Array [
    -   "1-2",
    -   "3-0",
    -   "1-0",
    -   "4-1",
    -   "1-1",
    -   "1-0",
    -   "0-2",
    -   "1-2",
    -   "0-2",
    -   "2-0",
    +   "[object Promise] 1-2 [object Promise]",
    +   "[object Promise] 3-0 [object Promise]",
    +   "[object Promise] 1-0 [object Promise]",
    +   "[object Promise] 4-1 [object Promise]",
    +   "[object Promise] 1-1 [object Promise]",
    +   "[object Promise] 1-0 [object Promise]",
    +   "[object Promise] 0-2 [object Promise]",
    +   "[object Promise] 1-2 [object Promise]",
    +   "[object Promise] 0-2 [object Promise]",
    +   "[object Promise] 2-0 [object Promise]",
]

您似乎收到了未处理的承诺。

我认为您可以使用 Async 和 await - 这将在您发送 get 请求时阻止您的代码编译。让代码等待直到请求完成,直到它继续编译。

这是一篇可以帮助您入门的文章 link:)

https://dev.to/tutrinh/basic-using-async-and-await-with-axios-ad5

[编辑]

这是一个粗略的想法 - 希望这能有所帮助。

const fetchTeamName = async(teamId) => {
    try{
        const response = await axios.get(`https://soccer.sportmonks.com/api/v2.0/teams/${teamId}?api_token=${apiKey}`)
        return response.data.data.name
    }  
}

正如有人已经提到的; axios returns 一个承诺。承诺是 javascript 的基本组成部分。你应该阅读 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise 。以下行导致了问题(这不是问题;它就是 javascript 的行为方式)

      const homeSide = fetchTeamName(homeTeamId).then((res) => {
        return res;
      });
      const awaySide = fetchTeamName(awayTeamId).then((res) => {
        return res;
      });

为了克服这个问题,您可以将函数调用包装在异步中。即

async function fetchFullTimeHeadToHeadScore(...){...}

然后使用 await

      const homeSide = await fetchTeamName(homeTeamId)
      const awaySide = await fetchTeamName(awayTeamId)

最好在使用该解决方案之前先了解 promises。祝你好运

如果您使用 await 等待承诺而不是使用 then,它可能更容易阅读(和编写)。

const res = await axios.get(`xxxx`)
const scores = res.data.data;

警告 - 你没有解释你打算 运行 这段代码的位置,以及你的构建过程是什么(如果有的话)。如果不使用 Babel 或 esbuild 等工具将现代 JavaScript 转换为与多种浏览器兼容的 JavaScript,await 并不总是可用。

但是,假设您 运行 在支持 async / await 的环境中运行您的代码,您还可以使用 Promise.all 函数来等待所有 3 个承诺完成。

async function fetchFullTimeHeadToHeadScore(homeTeamId, awayTeamId) {
    const homeTeamNamePromise = fetchTeamName(homeTeamId);
    const awayTeamNamePromise = fetchTeamName(awayTeamId);
    const scorePromise = fetchScore(homeTeamId, awayTeamId); // axios.fetch
    const results = await Promise.all([ homeTeamNamePromise, awayTeamNamePromise, scorePromise ]);
    const homeTeamName = results[0];
    const awayTeamName = results[1];
    const matches = results[2];
    return matches.map(match => `${homeTeamName} ${match.scores.ft_score} ${awayTeamName}`);
}

如果您真的需要使用 promise 来实现这一点,本文解释了:https://javascript.info/promise-chaining

相关代码如下:

// Make a request for user.json
fetch('/article/promise-chaining/user.json')
  // Load it as json
  .then(response => response.json())
  // Make a request to GitHub
  .then(user => fetch(`https://api.github.com/users/${user.name}`))
  // Load the response as json
  .then(response => response.json())
  // Show the avatar image (githubUser.avatar_url) for 3 seconds (maybe animate it)
  .then(githubUser => {
    let img = document.createElement('img');
    img.src = githubUser.avatar_url;
    img.className = "promise-avatar-example";
    document.body.append(img);

    setTimeout(() => img.remove(), 3000); // (*)
  });

在您的情况下,您似乎可以在代码中插入 Promise.all([ homeSide, res.data.data, awaySide ]); 以 return homeSideawaySide 的已解决承诺,以及实际res.data.data 的价值(即使这不是承诺)。

function fetchFullTimeHeadToHeadScore(homeTeamId, awayTeamId) {
  return axios
    .get(
      `https://soccer.sportmonks.com/api/v2.0/head2head/${homeTeamId}/${awayTeamId}?api_token=${apiKey}`
    )
    .then((res) => {
      const homeSide = fetchTeamName(homeTeamId)
      const awaySide = fetchTeamName(awayTeamId)
      return Promise.all([ homeSide, res.data.data, awaySide ]);
    })
    .then((data) => {
      return data[1].map((obj) => {
        return data[0] + " " + obj.scores.ft_score + " " + data[2];
      });
    })
    .then((scores) => {
      scores.length = 10;
      return scores;
    })
    .catch((err) => {
      console.log(err);
    });
}

fetchTeamName returns 一个未解析的 Promise,其 return 值只能在成功函数 (.then(onFulfillment, onRejection)) 中访问。我想你已经认识到了这一点,这就是你做 fetchTeamName(foo).then((res) => res) 的原因,但误解是你没有意识到这 return 是一个Promise!

没有没有方法来访问Promise实例方法(.then().catch()等)范围之外的结果.).

你可能会做类似的事情

      fetchTeamName(homeTeamId).then((homeSide) => {
        fetchTeamName(awayTeamId)
          .then((awaySide) => {
            return res.data.data.map((obj) => {
              return `${homeSide} ${obj.scores.ft_score} ${awaySide}`;
            });
          })
          .then((scores) => {
            scores.length = 10;
            return scores;
          });
      });

但你可能在想“等一下,awaySide 的值不依赖于 homeSide 的值,所以我为什么要等待那个 API 调用在我开始调用以获取 awaySide"?

的值之前完成

你这样想是对的!更好的解决方案使用 Promise.all:

      const homeSidePromise = fetchTeamName(homeTeamId);
      const awaySidePromise = fetchTeamName(awayTeamId);

      Promise.all([homeSidePromise, awaySidePromise])
        .then(([homeSide, awaySide]) => {
          return res.data.data.map((obj) => {
            return `${homeSide} ${obj.scores.ft_score} ${awaySide}`;
          });
        })
        .then((scores) => {
          scores.length = 10;
          return scores;
        });

这更好了,但它仍然难以阅读,而且并不比 Promise 成为 widely-supported 语言功能之前的 callback hell 好多少。

更现代的模式涉及使用 async/await。此语法仍“在幕后”使用 Promises,但可帮助您编写更具可读性的代码。我将使用 async/await 重写您的代码示例作为 reader.

的练习