题图 By Clm
在开发过程中我们经常使用Promise来处理异步,但是我们经常忽略Promise的错误处理。
今天带着大家来一起来梳理一下Promise处理错误的几种情况。
第一种情况是直接抛出error,在Promise中抛出错误只有throw和reject这两种方式,并且throw和reject抛出错误在Promise中没有区别,这两种方式都可以被catch所捕获,先看throw,代码如下:
new Promise((resolve,reject)=>{
throw "报错了哦"
}).catch((e=>{
console.log(e)
}))
打印如图:
再看通过reject来抛出错误,代码如下:
new Promise((resolve, reject) => {
reject("报错了哦")
}).catch((e => {
console.log(e)
}))
Promise.reject("报错了哦").catch(e=>{
console.log(e)
})
阅读源码发现throw和reject抛出的错误都会被catch所捕获,并且没有什么不同。
第二种情况,处理Promise调用链中的错误,如果有一个较长的Promise调用链,其中某个环节抛出错误,错误会被后续链中最近的一个catch所捕获,代码如下:
Promise.resolve(1)
.then(a => console.log(1))
.then(a => console.log(2))
.then(a => Promise.reject('error'))
.then(a => console.log(3))
.then(a => console.log(4))
.catch(err => console.log('err1', err))
.then(a => console.log(5))
.then(a => console.log(6))
.catch(err => console.log('err2', err))
.then(() => console.log('all done'))
打印结果如下:
阅读源码,我们发现调用链中第一个错误,被第一个catch函数所捕获,仔细观察打印结果,发现第一个错误发生的调用链后面的3、4被跳过了。
这是Promise调用链的一个特性,调用链中一旦发生错误,这个错误调用链后面的then链会被跳过,直接进入catch函数。
再仔细观察,我们发现第一个catch后面的then依然可以正常执行,这里大家需要注意,Promise调用链中发生错误后,会跳过后面的zhen链,进入catch函数,但是catch后面的then函数依然可以正常执行。
第三种情况,Promise.all的异常,一般处理并发的时候,我们需要使用Promise.all,但是如果all中有一个Promise实例出现异常,会导致全部结果被丢弃。如果这里的结果不符合你的预期一定要小心处理,看代码:
const tasks = [
Promise.resolve(1),
Promise.resolve(2),
Promise.reject("出错了哦"),
Promise.resolve(4),
Promise.resolve(5),
];
Promise.all(tasks)
.then(arr => console.log(arr))
.catch(err => console.log(err))
打印结果如下:
在这个例子中,我们虽然捕获了错误,但是其他结果全部被丢弃了,有的时候这不符合我们的预期,假如我们需要所有的结果,不管错误的还是正确的,该如何做呢?只需要对tasks数组中每一个promise实例都用catch处理一下,代码如下:
const tasks = [
Promise.resolve(1),
Promise.resolve(2),
Promise.reject("出错了哦"),
Promise.resolve(4),
Promise.resolve(5),
];
const taskeCatch = tasks.map(e=>e.catch(e=>e))
Promise.all(taskeCatch)
.then(arr => console.log(arr))
.catch(err => console.log(err))
打印结果如下:
有的同学看到这里可能会想到Promise.race的错误该如何处理,Promise.race虽然也是并发,但是其机制是只取一个结果,这个结果会按照正常的错误机制被捕获,如果做了处理错误处理,其执行路径会发生偏差,这主要是看代码的需求,看代码:
const tasks = [
Promise.reject("出错了哦"),
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(4),
Promise.resolve(5),
];
Promise.race(tasks)
.then(arr => {
console.log("执行的是then")
console.log(arr)
})
.catch(err => {
console.log("执行的是catch")
console.log(err)
})
执行结果如图:
我们看到错误被Promise链最后的catch函数所捕获。我们将代码修改一下,用catch处理tasks中每一个Promise实例。代码如下:
const tasks = [
Promise.reject("出错了哦"),
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(4),
Promise.resolve(5),
];
const taskeCatch = tasks.map(e=>e.catch(e=>e))
Promise.race(taskeCatch)
.then(arr => {
console.log("执行的是then")
console.log(arr)
})
.catch(err => {
console.log("执行的是catch")
console.log(err)
})
执行结果:
看结果,执行的是then,说明错误在第一个catch函数处被捕获了,catch后面的then链正常执行,所以执行了then函数。
以上便是在使用Promise时需要对错误处理时注意的地方,希望对你有所帮助。
引用资料:
Promise 错误处理
https://www.52cik.com/2018/04/30/promise-error.html