我还是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}`, {
headers: {
Authorization: "***",
},
})
.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>
答案 0 :(得分:0)
之所以不起作用,是因为您的两个函数都不是异步的。对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您可以阅读,因此您不必简单地阅读正式文档。
答案 1 :(得分:0)
尽量不要使用newCardsArray变量,只需将cardObject推入cardList即可。 在API调用完成之前,它正在分配空值。