问题背景:
我有一组list,包含了所有的预定id,现在我需要循环这组id去请求一个接口,以获取详情信息.
这里需要注意的点是:我需要的信息并不是一个接口可以请求完的,而是需要循环请求接口
那么,我如何确保这些接口全部请求完了才执行下面的操作呢?
list.map(item => {
axios.get(url).then(data => {
this.$set(item,"list",data.data.data)
});
});
list.map((item)=>{
console.log(item.list) // undefined
})
我们可以发现,如果不进行任何包装,仅仅是这样一个上下结构的逻辑,我们输出新插入的值时,发现全部都是undefined,因为请求是异步的.
解决方法:
使用Promise解决
let queue = list.map(item => {
return new Promise(resolve => {
axios.get(url).then(data => {
resolve(data.data.data);
});
});
});
Promise.all(queue).then(result => {
//TODO
//执行后续操作
});
Promise.all 方法会等待所有的 异步任务执行结束了,然后将所有任务的执行结果都统一的放到一个数组中,然后传给自己的 then
另外,Promise.all是异步请求并行操作
我们可以通过下面的代码证实一下
console.time("test")
var list = [1,2,3]
var queue =list.map((item)=>{
return new Promise((resolve,rejcet)=>{
setTimeout(() => {
resolve(item)
}, 1000);
})
})
Promise.all(queue).then((res)=>{
console.log(res)
})
console.timeEnd("test")
我们可以发现整个程序用了1s就运行完了,而非3s
如果你在使用Promise.all时出现了以下报错:cannot read property Symbol(Symbol.iterator)
那么请注意Promise.all的正确写法是:Promise.all([promise1,promise2,promise3])
而不是:Promise.all(promise1,promise2,promise3)
使用async/await结合Promise (串行)
async getlist() {
for (const item of list) {
const column = await getlistdetail(item)
}
//TODO
//后续操作
},
getlistdetail(item) {
return new Promise(resolve => {
axios
.get(url).then(data => {
this.$set(item, "roundlist", data.data.data);
resolve(data.data.data);
});
});
}
根据平凡朴素的吴亦凡在评论区提出的建议,我做出了一下优化
由于异步等待axios返回的本身就是一个Promise对象,所以重新再封装一层的必要性不大,可以直接return一个Promise
async getlistdetail(item) {
await axios.get(url)
.then(data => {
this.$set(item, "roundlist", data.data.data);
return data.data.data;
});
},
使用async/await结合Promise (串行)
最佳解决方法 该方法代码可读性比较高
async getlist() {
let list = await this.getlist();//获取id合集
const promises = list.map(x => this.getlistdetail(x));//根据每个id分别请求接口获取详情
for (const promise of promises) {
const column = await promise;
}
//TODO
//后续操作
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。