背景介绍
业务场景:后台有12个数据,前端有6个展示框,接口是传递一个参数,异步请求一个数据,但是这12个数据不是每个都有用,所以我们需要过滤掉无用数据,再展示给用户,提高用户体验(不能让用户走到这里渲染太慢),最后我才用的方式是:通过循环发起6个请求,然后将6个请求放到Promise.all中,当内容请求完成后,再对内容进行检测,有不合格就通过while循环发起一个请求,直到有合格数据为止,最后得到6个正确的数据再渲染到界面,在这期间我就踩了循环与async和await的坑;
整一个示例来模拟
整一个学生成绩表,统计不同成绩的人数,我们通过setTimeout来模拟在服务器上请求数据
let StudentGrade = {
"A": 5,
"B": 15,
"C": 8,
"D": 2,
};
const sleep = (time) => {
return new Promise((resolve) => {
setTimeout(resolve, time);
})
}
const getStudentGradeNum = (grade) => {//模拟服务器上发起请求
return sleep(1000).then(v=>StudentGrade[grade]);
}
console.log("grade",getStudentGradeNum("A").then(num=>{console.log(num)}));
最后总的统计一下
const result = async () => {
console.log("start");
let numA = await getStudentGradeNum("A");
console.log("A",numA);
let numB = await getStudentGradeNum("B");
console.log("B",numB);
let numC = await getStudentGradeNum("C");
console.log("C",numC);
let numD = await getStudentGradeNum("D");
console.log("D",numD);
console.log("end");
}
console.log("result",result());
在for循环中使用
let grade = ["A", "B", "C", "D"];
let numLoop = async () => {
for (let i = 0; i < grade.length; i++) {
const num = await getStudentGradeNum(grade[i]);
console.log("num",num);
}
}
console.log("numLoop",numLoop());
所以在for循环中await按照顺序执行,每1秒钟输出一个
在map中使用
let grade = ["A", "B", "C", "D"];
let numLoop = async () => {
console.log("start");
let nums = await grade.map(async item => {
const num = await getStudentGradeNum(item);
return num;
})
console.log("nums",nums);
console.log("end");
}
console.log("numLoop",numLoop());
如果你在 map 中使用 await,map 返回promise对象,你必须等待promise 的数组得到处理。 或者通过await Promise.all(nums)来完成此操作。
如下图:通过Promise.all输出结果就不同
在forEach循环中使用
let grade = ["A", "B", "C", "D"];
let numLoop = async () => {
console.log("start");
grade.forEach(async item => {
const num = await getStudentGradeNum(item);
console.log("num",num);
});
console.log("end");
}
console.log("numLoop",numLoop());
可以看到先输出了start和end,之后才输出了promise的东西,forEach只支持同步代码,所以不要在这里面使用async和await。
在filter循环中使用
let grade = ["A", "B", "C", "D"];
let numLoop = async () => {
console.log("start");
let nums = await grade.filter(async item => {
const num = await getStudentGradeNum(item);
return num > 5;
})
console.log("nums", nums);
console.log("end");
}
console.log("numLoop",numLoop());
实际上,在filter中使用await根本没有用,因为回调重视返回一个promise,相当于true,所以如果想要正确使用filter是需要其他的方式来配合得
总结一下
- 1、想要连续执行
await就用for循环 - 2、不要在
forEach中使用await,forEach只支持同步代码 - 3、在
map中使用await时,可以考虑使用Promise.all来处理promise对象 - 4、在
filter中使用await时,可以先用map处理后,再使用filter