关于trycatch的运行机制
当程序运行到try catch里面时,如果未报错,则忽略catch中的代码,若报错,则不执行try报错内容后面的代码,转而执行catch中的代码。
什么时候try catch 才能捕获到异常?
能捕捉到的异常必须是线程执行已经进入 try catch 但 try catch 未执行完的时候抛出来的
1,当语法错误时,不能捕获
因为语法错误是在语法检查阶段就报错了,线程执行尚未进入 try catch 代码块,自然就无法捕获到异常。 例如:
try{
a.
}catch(e){
console.log("error",e);
}
// output
Uncaught SyntaxError: Unexpected token '}'
复制代码
2,语法正确,线程进入try catch中时,可以捕获
function d(){a.b;}
try{
d();
}catch(e){
console.log("error",e);
}
// output
error ReferenceError: a is not defined
复制代码
代码执行进入了 try catch ,执行 d() 方法的时候,线程执行处在 try 里面,所以能捕捉到。
3,异步无法捕获
try{
setTimeout(()=>{
console.log(a.b);
}, 100)
}catch(e){
console.log('error',e);
}
console.log(111);
//output
111
Uncaught ReferenceError: a is not defined
复制代码
因为,setTimeout是异步函数,而try catch其实是同步顺序执行的代码,等setTimeout里面的事件进入事件队列的时候,主线程已经离开了try catch,所以try catch是无法捕获异步函数的错误的。
4.Promise异常无法捕获
// 异步,微任务
try {
new Promise(() => {
throw new Error('new promise throw error');
});
} catch (error) {
console.log(error);
}
复制代码
try-catch 主要用于捕获异常,注意,这里的异常,是指同步函数的异常,如果 try 里面的异步方法出现了异常,此时catch 是无法捕获到异常的,原因是因为:当异步函数抛出异常时,对于宏任务而言,执行函数时已经将该函数推入栈,此时并不在 try-catch 所在的栈,所以 try-catch 并不能捕获到错误。对于微任务而言,比如 promise,promise 的构造函数的异常只能被自带的 reject 也就是.catch 函数捕获到。
如果想要捕获Promise异常
- 1.Promise异常并不是绝对不能被捕获到的,如下
async function fn() {
try {
await new Promise(() => {
throw new Error('new promise throw error');
});
} catch (error) {
console.log(error);
}
}
fn()
复制代码
代码运行结果
这次Promise异常能被捕获到,是因为async和await
,正常不加async,await的时候,执行promise后,在等待promise回调的时候,try,catch已经执行完了,所以捕获不到,然而加了async和await后,try,catch必须等promise的回调执行完后,才能继续往下走,这个时候trycatch没执行完,promise抛出异常,自然而然能被catch捕获到
- 2.关于promise异常到底是被catch捕获还是.catch捕获
接下来我们把代码修改一下
async function fn() {
try {
await new Promise(() => {
throw new Error('new promise throw error');
}).catch(error=>{
console.log('.catch',error);
})
} catch (error) {
console.log('try,catch',error);
}
}
fn()
复制代码
.catch大家都知道,用来捕获promise异常,当我们有了.catch,错误在进入catch之前,就被.catch捕获到了,所以不会再往下走(可能有点绕,.catch是Promise异常捕获机制,不带. 是try,catch)
代码运行结果如下
到这里,我们可以发现,这个错误被.catch捕获到了,那如果我们不抛出一个错误,直接返回一个reject 会怎么样呢
async function fn() {
try {
const res = await new Promise((resove,reject) => {
return reject('捕获到了')
}).catch(error=>{
console.log('被promise.catch',error);
})
} catch (error) {
console.log('被try,catch',error);
}
}
fn()
复制代码
运行结果
Promise异常,如果写了.catch,就会被优先.catch捕获到,如果没有,那么就会被try,catch捕获到,
总结
通过上面分析,我们得出能被 try catch 捕捉到的异常,必须是在报错的时候,线程执行已经进入 try catch 代码块,且处在 try catch 里面,这个时候才能被捕捉到。 并且,try,catch如果使用async和await,也是可以捕获到Promise异常的,但我们不推荐,毕竟,Promise异常有它自己的.catch来捕获,而且更好用,不是吗?