如何解析在承诺链中调用 axios 获取请求的多个函数?



>基本上,我正在尝试编写一个函数,该函数将返回团队得分列表,并在分数旁边显示团队名称。但是,由于检索团队名称的函数返回挂起的承诺,因此我永远无法在控制台中看到名称。

我如何解决这些承诺,以便在承诺链的下一个.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]",
]

如果你使用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}`);
}

如果你真的需要用承诺来解决这个问题,这篇文章解释一下: 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 ]);以返回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);
});
}

看起来您正在收到未处理的承诺。

我认为您可以使用异步和等待 - 这将在您发送get请求时阻止您的代码编译。使代码等到请求得到满足,直到它继续编译。

这是一篇文章的链接,可以帮助您开始使用它:)

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
}  
}

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

无法访问超出其实例方法范围(.then().catch()等)的Promise的结果。

你可能会做这样的事情

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成为广泛支持的语言功能之前获得的回调地狱好多少。

更现代的模式涉及使用async/await.此语法仍然使用Promise的"幕后",但可以帮助您编写更具可读性的代码。我将使用async/await重写您的代码示例作为读者的练习。

正如有人已经提到的;axios返回一个承诺。承诺是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)

在使用解决方案之前,最好先了解承诺。祝你好运

相关内容

  • 没有找到相关文章

最新更新