如何解决在 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 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);
});
}
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
。此语法仍“在幕后”使用 Promise
s,但可帮助您编写更具可读性的代码。我将使用 async
/await
重写您的代码示例作为 reader.
的练习
基本上我正在尝试编写一个函数,该函数将 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 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);
});
}
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
。此语法仍“在幕后”使用 Promise
s,但可帮助您编写更具可读性的代码。我将使用 async
/await
重写您的代码示例作为 reader.