[掘金] 多点世界-面试官:请用一句话描述 try catch 能捕获到哪些 JS 异常

之前一直没有想过到底什么异常会被 try…catch 捕捉到,通过 多点世界 的这篇文章,对这个问题有了清晰的认识,觉得有必要做一个学习记录。

首先,是简单的一句话概括:

能捕捉到的异常,必须是线程执行已经进入 try catch 但 try catch 未执行完的时候抛出来的

文章中举的例子包括几种情况:

  • 语法检查阶段的语法异常
  • 异步执行中的异常
  • Promise

语法异常

例1中属于语法检查阶段的语法异常,报错时不在 try…catch 线程执行过程中,不会被 try…catch 捕捉到:

  1. try{
  2. a.
  3. }catch(e){
  4. console.log("error",e);
  5. }
  6. // output
  7. Uncaught SyntaxError: Unexpected token '}'

例2和例3中函数执行时语法异常,此时已在 try…catch 线程执行过程中,会被捕获:

  1. try{
  2. function d(){a.b;}
  3. d();
  4. }catch(e){
  5. console.log("error",e);
  6. }
  7. // output
  8. error ReferenceError: a is not defined
  1. function d(){a.b;}
  2. try{
  3. d();
  4. }catch(e){
  5. console.log("error",e);
  6. }
  7. // output
  8. error ReferenceError: a is not defined

若函数执行在 try…catch 之外,则不会被 try…catch 捕获,例如:

  1. try{
  2. function d(){a.b;}
  3. }catch(e){
  4. console.log("error",e);
  5. }
  6. console.log(111);
  7. d();
  8. // output
  9. 111
  10. Uncaught ReferenceError: a is not defined

异步方法中的异常

  1. try{
  2. setTimeout(()=>{
  3. console.log(a.b);
  4. }, 100)
  5. }catch(e){
  6. console.log('error',e);
  7. }
  8. console.log(111);
  9. //output
  10. 111
  11. Uncaught ReferenceError: a is not defined

setTimeout 中的代码是在 100ms 后执行的,此时 try…catch 代码块已经执行完成, console.log(111) 都已执行,也就是说已经不处于 try…catch 线程中了,所以 setTimeout 中的异常不会被 try…catch 捕获。

Promise 中的异常

  1. try{
  2. new Promise(function (resolve, reject) {
  3. a.b;
  4. }).then(v=>{
  5. console.log(v);
  6. });
  7. console.log(111);
  8. }catch(e){
  9. console.log('error',e);
  10. }
  11. console.log(222);
  12. // output
  13. 111
  14. 222
  15. Uncaught (in promise) ReferenceError: a is not defined

这里 try…catch 没有捕捉到异常,是因为 Promise 内部有捕获异常的处理(异常会传到 .catch 中),也就没有抛出到外部的 try…catch。Promise 内部具体实现可以参考一些 Promise polyfill 代码,例如 promise[core-js]promise

async/await

那为什么 await 又需要 try…catch 捕捉异常呢?语句执行到 await 时,必须等到 await 后的 Promise 有了返回值,才会执行下一行代码,如果有错误就会抛出。也就是 async 函数执行时,进程依然在 try…catch 内部,所以可以捕捉异常。