问题背景:我有一组包含所有预定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})我们可以发现,如果不做任何封装,就是这样一个顶层和底层结构的逻辑。当我们输出新插入的值时,我们发现它们都是未定义的,因为请求是异步的。解决方法:使用Promise解决letqueue=list.map(item=>{returnnewPromise(resolve=>{axios.get(url).then(data=>{resolve(data.data.data);});});});Promise.all(queue).then(result=>{//TODO//执行后续操作});Promise.all方法会等待所有异步任务执行完毕,然后将所有任务的执行结果放入一个数组中,然后传递给自己的then。另外,Promise.all是一个并行操作的异步请求。我们可以通过下面的代码来确认。console.time("test")varlist=[1,2,3]varqueue=list.map((item)=>{returnnewPromise((resolve,rejcet)=>{setTimeout(()=>{resolve(item)},1000);})})Promise.all(队列).then((res)=>{console.log(res)})console.timeEnd("test")我们可以发现整个程序运行时间为1s,而不是3s。如果使用Promise.all,会出现以下错误:cannotreadpropertySymbol(Symbol.iterator)那么请注意Promise.all的正确写法是:Promise.all([promise1,promise2,promise3])而不是:Promise.all(promise1,promise2,promise3)使用async/await结合Promise(serial)asyncgetlist(){for(constitemoflist){constcolumn=awaitgetlistdetail(item)}//TODO//后续operations},getlistdetail(item){returnnewPromise(resolve=>{axios.get(url).then(data=>{this.$set(item,"roundlist",data.data.data);resolve(data.data.data);});});}根据吴亦凡在评论区的建议,做了一些优化由于异步等待axios返回本身就是一个Promise对象,所以不需要重新封装一层,直接返回一个Promise即可asyncgetlistdetail(item){awaitaxios.get(url).then(data=>{this.$set(item,"roundlist",data.data.data);returndata.data.data;});},bestsolutionusingasync/awaitcombinedwithPromise(serial)方法该方法的代码更具可读性asyncgetlist(){letlist=awaitthis.getlist();//获取id集合constpromises=list.map(x=>this.getlistdetail(x));//请求接口根据每个id获取详情for(constpromiseofpromises){constcolumn=awaitpromise;}//TODO//后续操作}
