一、背景:
在公司项目写后端接口需要返回一串对象数组,每一项需要异步获取数据库中的关联数据,在forEach遍历中async/await实现不了
先来一个例子
const arr = [1,2,3,4]
arr.forEach(item=>{
setTimeout((item)=>{
// console.log(item)
item+=1
},0)
})
打印不出结果
再来一个async/await的例子
const promiseFn = (e) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(e)
},500)
})
}
const fun = ()=>{
let arr = [1, 2, 3, 4]
arr.forEach(async item => {
const res = await promiseFn(item)
console.log(res);
});
console.log('end');
}
//end
//1
//2
//3
//4
可见end先执行了 ,这样会导致什么结果?如果我在这进行某一些数据推进
const fun = ()=>{
let arr = [1, 2, 3, 4]
let newArr = []
arr.forEach(async item => {
const res = await promiseFn(item)
newArr.push(res)
});
console.log(newArr);
console.log('end');
}
fun()
打印结果是这样的:
//[]
//end
同样的操作如果用for
const fun = async () => {
let arr = [1, 2, 3, 4]
let newArr = []
for (let i = 0; i <= arr.length - 1; i++) {
const res = await promiseFn(arr[i])
newArr.push(res)
}
console.log(newArr);
console.log('end');
}
fun()
打印结果是正常的
//[1,2,3,4]
//end
上网查了资料发现,forEach中不可以进行异步操作,为什么?先上解决办法吧,毕竟把工作做好优先才能更好的摸鱼向leader汇报~
二、解决办法:
-
使用
for
、for-in
、for-of
A.
for
百搭B.
for-in
使用object,如果用for-in遍历数组,可能会出现一些问题比如:
const = [1,2,3] for (let index in arr) { let res = index + 1 console.log(res) } //打印结果为01 11 21
因为
index
索引为字符串型数字,不能直接进行几何运算使用for in会遍历数组所有的可枚举属性,包括原型
C.
for-of
适用遍历数/数组对象/字符串/map/set等拥有迭代器对象(iterator)的集合,但是不能遍历对象,因为没有迭代器对象,但如果想遍历对象的属性,你可以用for in循环(这也是它的本职工作)或用内建的Object.keys()方法 -
Promise.all + Map
const fun = async (data)=>{
let newArr = []
await Promise.all(data.map(async (item)=> {
const res = await promiseFn(item);
newArr.push(res)
}));
console.log(newArr);
console.log('end');
}
fun(arr)
//[1,2,3,4]
//end
这样也是可以解决问题的,具体看业务需求
三、问题原因
完成任务之后我们再看看为什么会这样
咱们进入forEach源码看看
这里传入一个回调函数返回空值,还有可选的参数
网上随便复制一份手写forEach来进行参考
Array.prototype.myForEach = function (fn, thisValue) {
if (typeof fn !== 'function') {
throw new Error(`${fn} 不是一个函数`)
}
if ([null, undefined].includes(this)) {
throw new Error(`this 是null 或者 undefined`)
}
const arr = Object(this)
for (let i = 0; i < arr.length; i++) {
fn.call(thisValue, arr[i], i, arr)
}
}
所以就相当于fn是一个异步函数,但是在foreach里面包裹起来并没有在相应地加上await在每一个fn身上,就会导致这个问题的产生