Promise.prototype.catch()
Promise.prototype.catch()方法是用于指定发生错误时的回调函数
getJSON('/posts.json').then(function(posts) { // ... }).catch(function(error) { // 处理 getJSON 和 前一个回调函数运行时发生的错误 console.log('发生错误!', error); });
上边代码中,getJSON( )方法返回一个Promise对象,如果该对象状态为resolved,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch( )方法指定的回调函数,处理这个错误。另外,then( )方法指定的回调函数,如果运行中抛出错误,也会被catch( )方法捕获。
p.then((val) => console.log('fulfilled:', val)) .catch((err) => console.log('rejected', err)); // 等同于 p.then((val) => console.log('fulfilled:', val)) .then(null, (err) => console.log("rejected:", err));
下面是一个例子
const promise = new Promise(function(resolve, reject) { throw new Error('test'); }); promise.catch(function(error) { console.log(error); }); // Error: test
上边代码中,promise抛出一个错误,就被catch方法指定的回调函数捕获。
Promise对象的错误具有冒泡的性质,会一直向后传递,直到被捕获为止。
getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL); }).then(function(comments) { // some code }).catch(function(error) { // 处理前面三个Promise产生的错误 });
上边的代码中,一共有三个Promise对象:一个由getJSON( )产生,两个由then( )产生。它们中,任何一个抛出错误,都会被最后一个catch( )捕获。
一般来说,不在then()方法里面定义Reject状态的回调函数(即then的第二个参数),总是使用catch方法。
// bad promise .then(function(data) { // success }, function(err) { // error }); // good promise .then(function(data) { //cb // success }) .catch(function(err) { // error });
上边的代码,第二种写法优于第一种,理由是第二种写法可以捕获前面then方法执行中的错误。因此,建议总是使用catch()方法,而不是使用then( )方法的第二个参数。
与传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise对象抛出的错误不会传递到外层代码,即不会有任何反应,
const someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行会报错,因为x没有声明 resolve(x + 2); }); }; someAsyncThing().then(function() { console.log('everything is great'); }); setTimeout(() => { console.log(123) }, 2000); // Uncaught (in promise) ReferenceError: x is not defined // 123
上边的代码中,someAsyncThing( )函数产生的Promise对象,内部有语法错误,浏览器运行到这一行,会打印出错误提示,但是不会退出进程,终止脚本运行,2s之后还是会输出123。 这就是说,Promise内部的错误不会影响到Promise外部的代码,通俗的说法就是“Promise 会吃掉错误”
这个脚本放在服务器执行,退出码是0(即表示执行成功)。不过,Node.js有一个unhandleRejection事件,专门监听未捕获的reject错误,上边的脚本会触发这个事件的监听函数,可以在监听函数里面抛出错误。
process.on('unhandledRejection', function (err, p) { throw err; });
上边的代码中,unhandleRejection事件的监听函数有两个参数,第一个是错误对象,第二个是报错的Promise实例,它可以用来了解发生错误的环境信息。
注意,Node 有计划在未来废除unhandleRejection事件。如果Promise内部有未捕获的错误,会终止进程,并且进程的退出码不为0.
一般总是建议,Promise对象后面要跟catch方法,这样可以处理Promise内部发生的错误。catch( )方法返回的还是一个Promise对象,因此后面还可以接着调用then()方法。
const someAsyncThing = function() { return new Promise(function(resolve, reject) { // 下面一行会报错,因为x没有声明 resolve(x + 2); }); }; someAsyncThing() .catch(function(error) { console.log('oh no', error); }) .then(function() { console.log('carry on'); }); // oh no [ReferenceError: x is not defined] // carry on
上边的代码运行完catch( )方法指定的回调函数,会接着运行后面那个then()方法指定的回调函数,如果没有报错,则会跳过catch( )方法
如下:
Promise.resolve() .catch(function(error) { console.log('oh no', error); }) .then(function() { console.log('carry on'); }); // carry on
上面的代码因为没有报错,跳过了catch()
方法,直接执行后面的then()
方法。此时,要是then()
方法里面报错,就与前面的catch()
无关了。
catch()方法之中,还能再抛出错误
someAsyncThing().then(function() { return someOtherAsyncThing(); }).catch(function(error) { console.log('oh no', error); // 下面一行会报错,因为y没有声明 y + 2; }).catch(function(error) { console.log('carry on', error); }); // oh no [ReferenceError: x is not defined] // carry on [ReferenceError: y is not defined]
上面代码中,第二个catch()
方法用来捕获前一个catch()
方法抛出的错误