在开发中遇到这样的一个问题,在map里面使用await,导致输出的结果顺序乱序。
正确的输出结果:
错误的结果输出:
从结果可以看出,“佟明” 应该在数组的第四个位置,但是结果的输出却是在第六个位置。
// **** 原代码 ****
// 将 await 放入 map 中的代码实例
approvePeopleList.map(async (item) => {
const data = {
"pageNo": 1,
"pageSize": 10,
"orgId": item.userId
}
try {
const res = await orguser(data)
orguserList.value.push(res.data.records[0]?.name ?? '暂无数据')
} catch (error) {
console.log(error);
}
})
为什么造成这样的结果?
查询了 MDN 中对 map 方法的描述,是这样描述的。
map
方法会给原数组中的每个元素都按顺序调用一次callbackFn
函数。
按照这个描述,map 会创建多个回调函数,每个回调函数上会添加上 async、await:
// map 遍历后会按顺序调用回调函数
async (item) => {
const data = {
"pageNo": 1,
"pageSize": 10,
"orgId": item.userId
}
const res = await orguser(data)
orguserList.value.push(item.data.records[0]?.name ?? '暂无数据')
}
async (item) => {
const data = {
"pageNo": 1,
"pageSize": 10,
"orgId": item.userId
}
const res = await orguser(data)
orguserList.value.push(item.data.records[0]?.name ?? '暂无数据')
}
async (item) => {
const data = {
"pageNo": 1,
"pageSize": 10,
"orgId": item.userId
}
const res = await orguser(data)
orguserList.value.push(item.data.records[0]?.name ?? '暂无数据')
}
造成乱序的原因:
由于各个回调函数之间的关系是独立的,所以他们的执行顺序是无法保证的,进而导致我们的返回结果造成乱序。
解决办法:
最终想到了 promise.all
来解决,因为 promise.all
接收一个数组类型,输入的所有 promise 的 resolve 回调的结果是一个数组。而且他的机制是,数组内的后一个 promise 的返回不需要依赖前一个 promise 的状态,只需要保证生成 promise 对象的函数是有序的即可。恰巧,map 就只能保证依次去创建并执行回调函数,而不会去在意结果返回。
// **** 修改后的代码 ****
// 收集所有异步任务到 list 数组中
const list = approvePeopleList.map(async (item) => {
const data = {
"pageNo": 1,
"pageSize": 10,
"orgId": item.userId
}
const res = await orguser(data)
return res
})
// map 返回的 promise 进行集中处理, map 得到了一个个的 Promise 实例化对象
Promise.all(list).then((res) => { // list => [promse1, promsise2, promise3]
console.log(res);
res.map((item: any) => {
orguserList.value.push(item.data.records[0]?.name ?? '暂无数据')
})
})
优势:
而且这样做的好处是大大提升了时间复杂度,由于map 创建的回调函数是并行执行的,所以 promise 数组创建完成的时间,就由消耗时间最久的请求决定。