异常
js
中执行出现错误会退出进程、终止脚本执行
console.log(x)
console.log(123)
// Uncaught ReferenceError: x is not defined
复制代码
try catch
try catch
捕获异常
try...catch
语句将能引发错误的代码放在try块中,并且对应一个响应,就能够捕获异常,不会影响后续代码运行。
try {
throw new Error('test')
}
catch (e) {
console.log(e)
}
console.log(1)
// Error: test
// 1
复制代码
try..catch
不能捕获异步的错误
try {
setTimeout(function () { throw new Error('test') }, 0)
}
catch (e) {
console.log(e)
}
// Uncaught Error: test
复制代码
可以配合 es6
的 async/await
捕获异步错误
async (req, res, next) => {
try {
const users = await database.users.get()
// do something
} catch (e) {
next(e)
}
}
复制代码
上面代码中,database.users.get()
是做一些异步操作,如果抛出异步错误,可以被 catch
方法捕获
Promise.prototype.catch()
Promise.prototype.catch()
方法是 Promise
异步操作状态变为 rejected
或者异步操作抛出错误,就会调用 catch
方法指定的回调函数,处理这个错误。另外,then
方法指定的回调函数,如果运行中抛出错误,也会被 catch
方法捕获。
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// Error: test
复制代码
上面代码中,promise
抛出一个错误,就被 catch
方法指定的回调函数捕获。
如果 Promise
状态已经变成 resolved
,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
复制代码
上面代码中,Promise
在 resolve
语句后面,再抛出错误,不会被捕获,等于没有抛出。因为 Promise
的状态一旦改变,就永久保持该状态,不会再变了。
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 会吃掉错误”。
不能捕获异步错误
const promise = new Promise(function (resolve, reject) {
setTimeout(function () { throw new Error('test') }, 0)
});
promise
.then(function (value) { console.log(value) })
.catch(function (error) { console.log(error) })
setTimeout(() => { console.log(123) }, 1000)
// Uncaught Error: test
// 123
复制代码
上面代码中,Promise
指定在下一轮“事件循环”再抛出错误。到了那个时候,Promise
的运行已经结束了,所以这个错误是在 Promise
函数体外抛出的,会冒泡到最外层,成了未捕获的错误,且并不会影响后续脚本执行。如果是在 setTimeout
调用 reject
则 catch
可以捕获到。