认识catch方法
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
new Promise (function (resolve, reject) {
//var rtn = x;
resolve("111")
}).then(function (result) {
var rtn = y;//--这里的错误也会被捕获
}).catch(function (error) {
console.log(error);
//ReferenceError: x is not defined
//ReferenceError: y is not defined
})
- 上面代码中,通过构造器方法返回一个 Promise 对象,如果该对象状态变为resolved,,则会调用then()方法指定的回调函数;如果异步操作抛出错误,状态就会变为rejected,就会调用catch()方法指定的回调函数,处理这个错误。
- 另外,then()方法指定的回调函数,如果运行中抛出错误,也会被catch()方法捕获。
p1.then(function (result) {
var rtn = y;//--这里的错误也会被捕获
}).catch(function (error) {
console.log(error);
//ReferenceError: y is not defined
})
// 等同于
p1.then(function (result) {
var rtn = y;
}).then(null, function (error) {
console.log(error);
//ReferenceError: y is not defined
})
案例剖析
var p1 = new Promise (function (resolve, reject) {
throw new Error("test"); //--报错就会被catch捕获
})
p1.then(function (result) {
console.log(result);
}).catch(function (error) {
console.log(error);
})
- 上面代码中,promise抛出一个错误,就被catch()方法指定的回调函数捕获。注意,上面的写法与下面两种写法是等价的。
//写法1
var p1 = new Promise (function (resolve, reject) {
try {
throw new Error("test")
} catch (e) {
reject(e)
}
})
p1.then(function (result) {
console.log(result);
}).catch(function (error) {
console.log(error);
})
//写法2
var p1 = new Promise (function (resolve, reject) {
reject(new Error("test"));
})
p1.then(function (result) {
console.log(result);
}).catch(function (error) {
console.log(error);
})
- 比较上面两种写法,可以发现reject()方法的作用,等同于抛出错误。
无效错误
如果 Promise 状态已经变成resolved,再抛出错误是无效的。
var p1 = new Promise (function (resolve, reject) {
resolve("ok")
throw new Error("test");
})
p1.then(function (result) {
console.log(result); //ok
}).catch(function (error) {
console.log(error);
})
- 上面代码中,Promise 在resolve语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。
冒泡性质
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
getJSON('/post/1.json').then(function(post) {
return getJSON(post.commentURL);
}).then(function(comments) {
// some code
}).catch(function(error) {
// 处理前面三个Promise产生的错误
});
好的习惯
一般来说,不要在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方法执行中的错误,也更接近同步的写法(try/catch)。因此,建议总是使用catch()方法,而不使用then()方法的第二个参数。
Promise 会吃掉错误
跟传统的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 对象,内部有语法错误。浏览器运行到这一行,会打印出错误提示ReferenceError: x is not defined,但是不会退出进程、终止脚本执行,2 秒之后还是会输出123。这就是说,Promise 内部的错误不会影响到 Promise 外部的代码,通俗的说法就是“Promise 会吃掉错误”。
catch()方法的返回值也是返回一个Promise对象
一般总是建议,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()方法。
catch方法中,还能继续抛出错误
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing().then(function() {
return someOtherAsyncThing();
}).catch(function(error) {
console.log('oh no', error);
// 下面一行会报错,因为 y 没有声明
y + 2;
}).then(function() {
console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
上面代码中,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()方法抛出的错误。