如何解决VueJS中与GET请求的异步性
我还是VueJS的新手。因此,我正在尝试向git API发出GET请求。首先,我提出了一个按照关注者数量对用户进行排序的请求,该请求以用户登录的降序检索出一个数组。之后,我对每个登录值都发出另一个GET请求,以获取更深入的数据,例如头像url,存储库计数等。问题是,而且我通常仍在处理异步问题,因为某些请求的执行速度比其他情况下,我的新对象数组在关注者数量方面变得混乱。我正在尝试执行sort()方法,但似乎无法弄清在js流中运行每个函数的顺序。有人可以帮我吗?
这是我正在使用的两个组件:
Home.vue
<template>
<div>
<div class="header">
<h1>Devfinder</h1>
<p>Find relevant developers from Github</p>
</div>
<div class="main">
<SearchBars :fetchLogins="fetchLogins" />
<CardList :cards="cards" />
</div>
</div>
</template>
<script>
import CardList from "./CardList";
import SearchBars from "./SearchBars";
import axios from "axios";
export default {
name: "Home",data() {
return {
loginList: [],cardList: [],cards: [],page: 1,};
},components: {
SearchBars,CardList,},methods: {
fetchLogins(language,location) {
axios
.get(
`https://api.github.com/search/users?q=location:${location}+language:${language}&sort=followers&order=desc&page=${this.page}&per_page=8`,{
headers: {
Authorization: "***",}
)
.then((res) => {
console.log(res.data);
this.loginList = res.data.items.map((item) => item.login);
console.log(this.loginList);
})
.catch((err) => console.log(err))
.then(() => this.setCardInfo())
.then(() => this.cards = this.cardList.sort((a,b) => b.followers - a.followers));
},setCardInfo() {
let newCardsArray = [];
this.cards = [];
this.cardList = [];
// Zera o state de cards e itera o array loginList fazendo um GET request e criando o objeto para o array cards
this.loginList.forEach((login) =>
axios
.get(`https://api.github.com/users/${login}`,})
.then((res) => {
const user = res.data;
const cardObject = {
id: user.id,name: user.name,avatar: user.avatar_url,bio: user.bio,followers: user.followers,repositories: user.public_repos,};
newCardsArray.push(cardObject);
})
);
// Por causa da assincronicidade,alguns objetos,mesmo com mais seguidores,acabam ficando atrás na ordem do array
// invoco um sort() em ordem descendente
this.cardList = newCardsArray;
},};
</script>
和我的SearchBars组件
<template>
<div>
<form @submit="onSubmit">
<p>Tech/Lang</p>
<input type="text" v-model="language" placeholder="Type a technology or language" />
<p>Location</p>
<input type="text" v-model="location" placeholder="Type the desired location" />
<input type="submit" value="FIND" />
</form>
</div>
</template>
<script>
export default {
name: "SearchBars",data() {
return {
language: '',location: ''
}
},methods: {
onSubmit(e){
e.preventDefault();
this.fetchLogins(this.language,this.location);
}
},props:["fetchLogins","getCardInfo"]
};
</script>
解决方法
之所以不起作用,是因为您的两个函数都不是异步的。对fetchLogins
而言,这无关紧要,因为没有任何等待。但是,由于在fetchLogins
中,您正在等待对setCardInfo
的调用,因此需要setCardInfo
是异步的。发生的是这一行:
.then(() => this.setCardInfo())
您的.then
链会启动this.setCardInfo
,但不会等到转移到链中的下一个.then
之前。这是因为setCardInfo
不会返回Promise,所以.then
立即解决。
有两种方法可以做到这一点。您可以保持代码的当前组织方式,并使this.setCardInfo
返回Promise;要么;您可以更改为async
/ await
的语法(实际上是相同的),并使您的代码更具可读性。
定义async
函数时,您真正要做的只是将其包装在return new Promise
中,该函数的返回值是resolve
的值。因此,这意味着您可以.then
使用该功能。 但是,等一下!!当一个函数异步时,您可以使用特殊关键字await
来告诉该函数“运行此行,等待其结束,然后继续前进” -实际上,您正在做的是.then
-其余的功能,而不必链接另一个.then
并添加另一个级别压痕。
在您的情况下,您可以使用的另一件事是Promise.all
:您向它传递了一组Promises(据我们所知,async
函数在幕后返回了!),并且只有在阵列中的所有功能都解决后,它才能解决其承诺。因此,您可以做类似的事情,
async function myFunc(arr) {
const responses = await Promise.all(arr.map(async item => {
const res = await fetch('api',{ body: item });
return await res.json();
});
}
,最后得到的是arr
项的响应的JSON数组。它所做的只是创建未解决的承诺数组,而Promise.all
只是等待它们全部解决。如果其中任何一个拒绝,则Promise.all
将拒绝。因此,当我在这里使用该范例时,我将其放在try
中的catch
/ map
中,因此希望您可以逐张处理它。 >
看看我提出的解决方案(这只是methods
部分):
methods: {
fetchLogins: async function(language,location) {
let res;
try {
res = await axios.get(
`https://api.github.com/search/users?q=location:${location}+language:${language}&sort=followers&order=desc&page=${this.page}&per_page=8`,{ headers: { Authorization: "90fa62d4dee8b02d363d83fccac86f3b7536492c" } }
);
} catch (err) {
console.error(err);
// deal w/ error,so the code below (dependent
// on 'res') doesn't run. Or just let it err out.
// up to you.
}
// None of this is async,so it doesn't need an await
console.log(res.data);
this.loginList = res.data.items.map(item => item.login);
console.log(this.loginList);
// Run the other function
this.cards = [];
this.cardList = [];
// Keeping this as a separate function,since I don't know how you're
// going to use it,but it could totally be be copied here.
// "this.cardList // = await Promise.all ..." is really just one
// line down there. Paste it here if you aren't gonna need it as a
// separate function
await this.setCardInfo();
this.cards = this.cardList.sort((a,b) => b.followers = a.followers);
},setCardInfo: async function () {
this.cardList = await Promise.all(this.loginList.map(async login => {
let res;
try {
res = axios.get(
`https://api.github.com/users/${login}`,{ headers: { Authorization: "90fa62d4dee8b02d363d83fccac86f3b7536492c" } }
);
} catch (err) {
console.errror(err);
// Deal w/ error (return undefined? "couldn't find user's info"?)
}
const user = res.data;
const cardObject = {
id: user.id,name: user.name,avatar: user.avatar_url,bio: user.bio,followers: user.followers,respositories: user.public_repos
};
// Resolve the Promise for this iteration of the map funciton
return cardObject;
}));
},},
我不是100%确信这对您有用,但是我认为我并未更改代码实际执行的任何操作,因此应该更改。如果没有,我希望对Promises和async
/ await
的解释能成为踏脚石。
我建议您查看非常棒的MDN,以获取有关此资源的信息。他们甚至有一个starter guide您可以阅读,因此您不必简单地阅读正式文档。
,尽量不要使用newCardsArray变量,只需将cardObject推入cardList即可。 在API调用完成之前,它正在分配空值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。