JavaScript中Promise的catch函数

原文:The Promise catch() Function in JavaScript

Promise的catch函数是一个很方便的语法糖,用于处理Promise中的错误。

JavaScript的Promise是一个代表异步操作的对象。Promise就像是一个还未计算完成的值的占位符,一旦异步操作失败,JavaScript会将Promise置为rejected状态catch()函数会在Promise变为rejected时进行调用。

1
2
3
4
5
const p = Promise.reject(new Error('Oops!'));

p.catch(err => {
err.message; // 'Oops!'
});

Promise链式操作

.catch()的一个主要好处是,可以捕获Promise链中任意一环发生的错误。

1
2
3
4
5
6
7
8
9
10
11
const p = Promise.resolve('Na');

return p.
then(str => str + ' Na').
then(str => str + ' Na').
then(str => str + ' Na').
then(() => { throw new Error('Batman!') }).
then(() => console.log('Will not print')).
catch(err => {
err.message; // 'Batman!'
});

也就是说可以在一个Promise链的最后加上catch(),来处理整条链上的错误。

重新抛出错误

try/catch类似,在.catch()中可以重新抛出错误。

1
2
3
4
5
6
7
const p = Promise.reject(new Error('Oops!'));

return p.
catch(err => { throw err; }). // 重新抛出错误
catch(err => {
err.message; // 'Oops!'
});

正因如此,在catch()中处理错误时,要特别小心未捕获的错误。如果传入.catch()的函数抛出错误,而没有后续的.catch(),会导致“未处理的Promise错误”。

拆包错误

如果在.catch()中返回一个值,那么awaitthen()会“拆包”这个值。

1
2
3
4
5
6
7
8
9
10
const p = Promise.reject(new Error('Oops!'));

const answer = await p.catch(() => 42);
answer; // 42

return p.
catch(() => 42).
then(answer => {
answer; // 42
});

换言之,在JavaScript中可以用像Golang的语法处理异步错误

1
2
3
4
const p = Promise.reject(new Error('Oops!'));

const err = await p.catch(err => err);
err.message; // 'Oops!'

与then()比较

catch()函数只是基于Promise的then()函数的语法糖。回忆一下then()的2个参数:

  • onFulfilled(): JavaScript会在底层异步操作成功后调用
  • onRejected(): JavaScript会在底层异步操作失败后调用

.catch(fn)相当于.then(null, fn),以下是catch()的最简单的polyfill:

1
2
3
Promise.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};

其实用.then()也能处理Promise的错误:

1
2
3
4
5
const p = Promise.reject(new Error('Oops!'));

return p.then(() => {}, function onRejected(err) {
err.message; // 'Oops!'
});