场景:在一个for循环中执行异步请求,请求结果最终需要在循环外部使用。
let targetData = [];
let originData = [1,2,3];
for ( let i = 0; i < originData.length; i++ ) {
// 这里执行异步ajax 我们用setTimeout模拟
setTimeout(() => {
targetData.pusn(i);
},0)
}
console.log(targetData); // []
由于异步代码执行是在主栈代码执行结束之后再执行,因此console.log(targetData)
在执行的时候for循环内部的异步代码并没有执行。因此也就在外部获取不到我们想要的数据。
解决方案:
1. 使用Promise.all()进行请求并发处理
let targetData = [];
let originData = [1,2,3];
let promises = originData.map((item) =>{
return new Promise((resolve, reject) => {
// 异步ajax 用setTimeout模拟
setTimeout(() => {
targetData.push(item);
resolve();
},0)
})
})
Promise.all(promises).then(() => {
console.log(targetData); // [1, 2, 3]
})
将每次的异步逻辑装在promises数组中。然后调用Promise.all()进行并行请求,然后就能在Promise.all()的then回调里获取到我们想要的值。但是这样会有一个问题,就是当promises数组中其中一个请求挂掉了,那么永远也不能在Promise.all()的then回调里获取到数据。具体处理方法,在我的这篇文章里有叙述Javascript知识零散学习(面试篇)。
2. 使用async / await进行请求逐个处理
let targetData = [];
let originData = [1,2,3];
function getAsyncData(i){
return new Promise((resolve,reject) => {
setTimeout(() => {
targetData.push(i);
resolve();
}, 0)
})
}
async function initalRequest(){
for(let i = 0; i < originData.length; i++){
await getAsyncData(originData[i])
}
}
initalRequest().then(() => {
console.log(targetData); // [1,2,3];
})
这种方法逐一对异步请求进行处理,执行效率相对第一种较低,如果其中有一个请求挂掉,那么也不会在initalRequest()的then方法中获取数据,这个时候可以在getAsyncData方法中的Promise中进行catch捕获,和上面处理错误形式一样。这样就能正常获取到数据了。