实践[JavaScript] Promise.allSettled 函数的实现与应用

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)
}
相关推荐
lpfasd1231 小时前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
Data analyse4563 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai4 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
环境栈笔记4 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
赵大仁5 小时前
官网性能优化实战:LCP 3.2s → 2.1s、CLS 0.107 → 0,以及被我推翻的 6 个判断
前端·性能优化·cls·lcp·core web vitals
xiancai_xianyu5 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
小羊没烦恼!5 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
史瓦辛格5 小时前
给 DeepSeek Harness 写费用插件:把「这次会话花了多少钱」算准
前端·deepseek
星光不问赶路人5 小时前
Vue 3 + TypeScript 中 enum 的使用实践
前端·vue.js
鸥梨菌Honevid5 小时前
UVM 中 REQ 和 RSP 类型详解:从通信模型到 item_done 与 put_response
java·前端·servlet