>基本上,我正在尝试编写一个函数,该函数将返回团队得分列表,并在分数旁边显示团队名称。但是,由于检索团队名称的函数返回挂起的承诺,因此我永远无法在控制台中看到名称。
我如何解决这些承诺,以便在承诺链的下一个.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 ]);
以返回homeSide
和awaySide
的已解决承诺,以及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)
在使用解决方案之前,最好先了解承诺。祝你好运