一个很有趣的问题,Promise.all 批量执行中途出错如何继续执行?

年底了,准备删库跑路了,聊了几家公司,当然大部分公司基本上看我5年多经验,一般也不问技术问题了,不过也不是完全没有,这不,遇到了一家,问了一个问题,我觉得非常有意思,记录下来,分享给大家!

问题

Promise.all 批量执行的时候,如何中途出错继续执行?

假设需求

比如有一个后台,有一个功能,叫做“账户管理”,然后呢,数据库有一个字段,叫“系统账户”,然后规则是:系统账户不允许删除;然后前端部分有一个批量删除功能,这个时候,假设人家批量删除的任务中,推入了一个“系统账户”,这个时候就会出现问题了!接口可能就会报错,告诉你这个数据不可以删除!

需求分析

在上述需求中,如果我们直接推入一个任务给 Promise.all 执行,假设选择了5条数据,第3条数据不可删除,假定数据如下:

['可删','可删','不可删','可删','可删']

这个时候如果直接执行,就会发现,用户勾选了5个,但实际就删除了2个(前两个),因为在第3个时候,报错了!然后后面就不执行了,但很显然,实操上,我们肯定是希望删除4个(即:第三个不删除)

如何实现

其实非常简单,就是你在推送任务队列的时候,单个任务的报错环节,也返回正确的,就是告诉 Promise.all,你别管这个到底错不错,我说他是对的,就行了,你走就行!

示例代码

以下代码是从我的项目理解直接截取出来的,

export default {
    methods: {
        /**
         * 批量删除
         */
        handleRemoveMultiRows() {
            this.$confirm({
                title: "批量删除确认",
                content: "是否删除您当前选中的数据?该操作不可恢复!请知悉!",
                onOk: () => {
                    const {selectedRowKeys} = this;

                    // 任务队列
                    const tasks = [];

                    // 推送任务
                    for (const id of selectedRowKeys) {
                        // 如果某个删除操作报错,不影响后续执行
                        tasks.push(removeUserById(id).catch(() => {
                            // 直接处理 removeUserById 的 catch,返回 Promise.resolve
                            // 即:任务出错了,但实际上我告诉 Promise.all 这条是正确的
                            // 当然,实操上肯定是返回固定的特定值,用于最终的统计
                            return Promise.resolve()
                        }));
                    }

                    // finally 是无论 Promise then 还是 catch 都执行
                    // 类似于jquery中ajax请求的 complete,就是不管你报错不报错,结束了就执行
                    Promise.all(tasks).finally(this.getData);
                }
            })
        },
    }
}

彩蛋

其实我挺讨厌面试官不讲需求不讲场景上来直接抛问题,我也做过面试官,因此,我来给大家来一个实际的需求,可以配合这个场景的!这样方便大家理解,不讲需求,纯粹的耍流氓!