前言
在平时开发过程中,通常遇到异常,浏览器会停止执行JS并抛出异常,但有时候我们并不想一些异常中断代码执行,就会用到try...catch...代码块来捕获JS异常,也方便我们定位错误调试代码,帮助我们及时解决bug,但你有没有想过,是不是在try代码块中写我们的代码,就能被catch抛出异常呢?
我们知道,一般在try代码块中,执行的代码若有异常,则可能被catch抛出异常,我说的是可能,那么,你能否用一句话来描述try...catch...能否正确捕获到JS异常?
在这里,先抛砖引玉吧:try catch能捕获到的异常,必须是JS代码在执行阶段时抛出的并且是处在try catch代码块中。
那么,我们下面来分析下try catch到底是怎么捕获异常的。主要分为三个阶段,即try catch 前、中、后(好像有点废话)
try catch之前
若在代码报错时,JS线程执行未进入try catch,则无法捕获异常。比如语法异常 syntaxError,因为语法异常是在语法检查阶段就报错了,JS代码还没开始执行,即没有在try catch代码块中执行,因此也就无法捕获到异常。如以下代码:
try { var a = null; a.} catch (e) { console.log(‘error’, e);}// Uncaught SyntaxError: Unexpected token '}'
try catch之中
代码执行阶段报错时,此时处于try 代码块之中,则能正确捕获到异常。如下代码,执行fn()方法时,JS执行的线程已经进入try代码块中,所以异常能被捕获到。
```jstry { function fn() { a.b } fn();} catch(e) { console.log(‘error’, e);}// error ReferenceError: a is not defined```
try catch之后
这里很显然代码执行报错时,JS执行完try catch了,此时是无法捕获到异常的。当然,我们说的try catch之后执行,除了在其之后调用之外,还有一种情况就是在try代码块中执行异步代码,了解JS事件队列,我们知道,try catch在主线程已经执行完毕了,才会去执行异步队列的代码,这个时候异步代码抛出的异常是无法被try catch捕获到错误的。如下代码:
try { setTimeout(()=>{ console.log(a.b); }, 100)} catch (e){ console.log('error',e);}console.log(123);// 123// Uncaught ReferenceError: a is not defined
Promise的异常捕获
我们知道Promise可以异步执行代码,但是在实例化Promise时,Promise传的参数是一个马上执行的函数,真正异步执行是其内部的状态转化机制,来等待执行的结果状态,通过then或catch来获取返回的结果。那么在Promise内部执行的代码抛出的异常能不能被try catch捕获呢?直接上代码运行看看:
try { new Promise((resolve, reject) => { a.b; }).then((res)=> { console.log(res); }, (e) => { console.log(‘promise error’, e); })} catch(e) { console.log(‘try catch error’, e);}// promise error ReferenceError: a is not defined
从以上代码运行结果可以看出,异常是被Promise自身捕获的,其实,Promise的异常是由reject方法或者Promise.prototype.catch来捕获的,并且不会往上抛出异常,故外层的try catch无法捕获到Promise抛出的异常。这里我们可以得出,就是尽量不要给Promise套上try catch,因为异常无法被往上抛出,用Promise自身提供的方法去捕获即可。
但是,是不是try catch就木有办法捕获Promise抛出的异常了吗?答案那当然是阔以捕获啦~我们看下面这段代码:
function a() { return new Promise((resolve, reject) => { setTimeout(() => { reject(1); }) })}try { await a();} catch(e) { console.log('error', e);}console.log(111);// error 1// 111
神奇的事情发生了,try catch能捕获到异常,其实这就归功于await,我们知道await后可执行一个异步代码,并且需要等到异步代码执行返回结果才会继续执行,所以执行a异步方法,等待结果返回后,此时JS代码执行还是停留在try catch代码块中,Promise通过reject方法抛出的异常就被捕获了。所以,一般在执行异步任务时,要在try catch中捕获异常,还是配合async/await用。
![a98d111c1c1c6844a7f42aadd21a4e9a.png](https://i-blog.csdnimg.cn/blog_migrate/fced07573643ed7c4a7a3a869537a23a.jpeg)
感谢您阅读我分享创作的文章,文章会同步在本人公众号【前端精神小伙】中,可关注阅读往期文章。
欢迎一起学习和交流,debug佳也将持续为大家分享更多前端技术干货。