18

问题背景:

我有一组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")

image.png
我们可以发现整个程序用了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
      //后续操作
}

无锡肖奈
186 声望7 粉丝

十八线野生程序猿 前端开发