Promise.allSettled 函数的作用是等待一组promise,并在所有等待的promise处理完成后,返回相对应的结果,结果以数组的形式传递给下一节点。
我们在开发项目时遇到一个需求,那就是多表单校验,并需要对每个报错的表单进行一些操作,同时在所有的表单处理完成后,将通过校验的表单上传给后台。
为了解决这个需求,我们实现了两种方案,一种是对每个表单的validate进行封装,并通过withResolvers
返回reject
自己手动处理每个异常,外部使用Primise.all
接收。而第二种就是通过Promise.allSettled
来实现多表单一部校验同步等待功能。这两种方式所实现的效果是一样的。但如果关注结果顺序,则二者返回的数据则会有些许区别
使用Promise.allSettled
实现
ts
/**
* 随机,对2取余,返回true,否则返回false
* @returns
*/
function validate(index: number) {
const flag = parseInt((Math.random() * 10).toFixed(0)) % 2
return new Promise((resolve, reject) => {
setTimeout(() => {
flag ? (resolve({ index, flag })) : reject({ index, flag })
}, Math.random() * 200)
})
}
function saveData(res: any) {
return Promise.resolve()
}
(async () => {
console.log('tset promise allsettled')
const res = await Promise.allSettled([validate(1), validate(2), validate(3), validate(4), validate(5)])
// 获取通过校验的表单
const list = res.filter(item => item.status === 'fulfilled')
// 保存操作
await saveData(list)
console.log(res)
/**
* [
* { status: 'fulfilled', value: { index: 1, flag: 1 } },
* { status: 'rejected', reason: { index: 2, flag: 0 } },
* { status: 'rejected', reason: { index: 3, flag: 0 } },
* { status: 'fulfilled', value: { index: 4, flag: 1 } },
* { status: 'rejected', reason: { index: 5, flag: 0 } }
* ]
*/
})()
我们基于Promise.all
封装的结果如下所示
ts
/**
* 随机,对2取余,返回true,否则返回false
* @returns
*/
function validate(index: number) {
const flag = parseInt((Math.random() * 10).toFixed(0)) % 2
return new Promise((resolve, reject) => {
setTimeout(() => {
flag ? (resolve({ index, flag })) : reject({ index, flag })
}, Math.random() * 200)
})
}
function saveData(res: any) {
return Promise.resolve()
}
function allSettled(args: Promise<any>[]) {
if (!Array.isArray(args)) {
throw Error("非数组")
}
const callList: Promise<any>[] = []
for (let index in args) {
function func() {
return new Promise((resolve) => {
const call = args[index]
call.then((res) => {
resolve({ status: 'fulfilled', value: res })
}).catch((res) => {
resolve({ status: 'reject', value: res })
})
})
}
callList.push(func())
}
return Promise.all(callList)
}
(async () => {
console.log('tset promise allsettled')
const res = await allSettled([validate(1), validate(2), validate(3), validate(4), validate(5)])
// 获取通过校验的表单
const list = res.filter(item => item.status === 'fulfilled')
// 保存操作
await saveData(list)
console.log(res)
/**
* [
* { status: 'fulfilled', value: { index: 1, flag: 1 } },
* { status: 'reject', value: { index: 2, flag: 0 } },
* { status: 'reject', value: { index: 3, flag: 0 } },
* { status: 'fulfilled', value: { index: 4, flag: 1 } },
* { status: 'fulfilled', value: { index: 5, flag: 1 } }
* ]
*/
})()
核心代码: 该函数是通过包裹一层Promise
并在异常时捕获异常,并通过resolve返回,最后通过all实现join,等待所有promise全部执行
ts
function allSettled(args: Promise<any>[]) {
if (!Array.isArray(args)) {
throw Error("非数组")
}
const callList: Promise<any>[] = []
for (let index in args) {
function func() {
return new Promise((resolve) => {
const call = args[index]
call.then((res) => {
resolve({ status: 'fulfilled', value: res })
}).catch((res) => {
resolve({ status: 'reject', value: res })
})
})
}
callList.push(func())
}
return Promise.all(callList)
}