中断Promise链的方法

在真实开发环境的情况下,有可能遇到一种情况就是,Promise链式处理数据,中间部分发现有数据错误,这时候就需要中断Promise链。

分析

一开始的想法是把执行函数中的reject包裹进数据中传递下去,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
new Promise(function(resolve, reject) {
resolve(reject)
}).then((reject) => {
console.log(1)
return reject
})
.then((reject) => {
console.log(2)
return reject
})
.then(() => {
console.log(3)
reject()
})
.then(() => console.log(4))
.catch((err) => console.log(err))

结果是失败的,依然会执行输出后面的4
原因是,因为在执行resove以后,该Promise的状态已经改变为Fulfilled状态,Promise状态的转换只能从Pending -> FulFilledPending -> Rejected

解决方案

1. 使用变量确定是否执行

设定一个Promise作用域以外的变量,来确定then中操作是否执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let continueRun = true
function thenTask(func) {
if (continueRun) {
func()
}
}
Promise.resolve()
.then(() => thenTask(() => {
console.log(1)
}))
.then(() => thenTask(() => {
console.log(2)
}))
.then(() => thenTask(() => {
console.log(3)
continueRun = false
}))
.then(() => thenTask(() => {
console.log(4)
}))

2. 调用Promise.reject

虽然当前Promise已经不能再转为rejected状态,但是可以通过返回一个新的Promise对象调用reject()方法来中断当前的Promise链

1
2
3
4
5
6
7
8
9
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => {
console.log(3)
return Promise.reject()
})
.then(() => console.log(4))
.catch((err) => console.log(err))

因为reject的本质其实就是抛出异常让catch捕获,因此Promise.reject抛出异常后就会中断当前执行中的任务链。需要注意的是,catch是会捕捉到return Promise.reject()的异常的,所以需要在catch中区分开中断的操作和其他异常。

3.抛出异常

跟方法2一样,直接抛出异常中断流程。

1
2
3
4
5
6
7
8
9
Promise.resolve()
.then(() => console.log(1))
.then(() => console.log(2))
.then(() => {
console.log(3)
throw new Error('break')
})
.then(() => console.log(4))
.catch((err) => console.log(err))