前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >面试官:用一句话描述 JS 异常是否能被 try catch 捕获到 ?

面试官:用一句话描述 JS 异常是否能被 try catch 捕获到 ?

作者头像
童欧巴
发布2020-06-24 16:03:44
1.1K0
发布2020-06-24 16:03:44
举报
文章被收录于专栏:前端食堂前端食堂

平常撸代码的时候,try catch 用的太多了,特别是一些 ”安全感" 低的人,基本是到处 try catch,生怕 JS 报错,然后页面整个挂掉了。

其实为啥会安全感低呢,是因为界限模糊。

所以,我们要做一个 “安全感” 高的码农[狗头][狗头][狗头]


  • 面试官:麻烦用一句话描述 JS 异常是否能被 try catch 到?
  • 面试者:异步方法无法捕捉到……
  • 面试官:不要背答案,麻烦用一句话描述 JS 异常是否能被 try catch 到!
  • 面试者:沉默 ing …………
  • 面试者:能捕捉到的异常必须是线程执行已经进入 try catch 但 try catch 未执行完的时候抛出来的。
  • 面试官:沉默 ing …………
  • 面试官:啥时候可以来上班?
  • 欢笑交谈中,拿到 offer …………

我们我们来分析下这个一句话描述 try catch 的含义。

主要分为三段:try catch 之前,之中,之后。

之前

代码报错的时候,线程执行未进入 try catch,那么无法捕捉异常。

比如语法异常(syntaxError),因为语法异常是在语法检查阶段就报错了,线程执行尚未进入 try catch 代码块,自然就无法捕获到异常。

例子 1:

代码语言:javascript
复制
try{
    a.
}catch(e){
    console.log("error",e);
}
// output
Uncaught SyntaxError: Unexpected token '}'

之中

代码报错的时候,线程执行处于 try catch 之中,则能捕捉到异常。

看如下例子:

  • 方法和执行都在 try 里面,能捕捉到异常。
代码语言:javascript
复制
try{
    function d(){a.b;}
   d();
}catch(e){
    console.log("error",e);
}
// output
error ReferenceError: a is not defined
  • 方法定义在外部,执行方法在 try 里面,能捕捉到异常
代码语言:javascript
复制
function d(){a.b;}
try{
   d();
}catch(e){
     console.log("error",e);
}
// output
error ReferenceError: a is not defined

上述报错的时机,都是代码执行进入了 try catch ,执行 d() 方法的时候,线程执行处在 try 里面,所以能捕捉到。

之后

代码报错的时候,线程已经执行完 try catch,这种不能捕捉到异常。

例子:

代码语言:javascript
复制
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 里面报错,实际上是 100ms 之后执行的代码报错,此时代码块 try catch 已经执行完成,111 都已经被执行了,故无法捕捉异常。

例子:

代码语言:javascript
复制
try{
   function d(){a.b;}
}catch(e){
     console.log("error",e);
}
console.log(111);
d();
// output
111
Uncaught ReferenceError: a is not defined

方法定义在 try catch 代码块里面,但是执行方法在 try catch 外,在执行 d 方法的时候报错,此时 try catch 已经执行完成,111 都已经被执行了,故而无法捕捉异常。

总结

能被 try catch 捕捉到的异常,必须是在报错的时候,线程执行已经进入 try catch 代码块,且处在 try catch 里面,这个时候才能被捕捉到。

如果是在之前,或者之后,都无法捕捉异常。

敲黑板:不要死记硬背,啥可以捕获,啥不能捕获!记住这一句话,永远不会忘!

Promise 没异常

相对于外部 try catch,Promise 没有异常!

例子 6:

代码语言:javascript
复制
try{
    new Promise(function (resolve, reject) {
        a.b;
    }).then(v=>{
        console.log(v);
    });
}catch(e){
    console.log('error',e);
}
// output
Uncaught (in promise) ReferenceError: a is not defined

看如上报错,线程在执行 a.b 的时候,事实上属于同步执行,try catch 并未执行完成,按理应该能捕捉到异常,这里为啥无法捕捉呢?

事实上,Promise 的异常都是由 reject 和 Promise.prototype.catch 来捕获,不管是同步还是异步。

核心原因是因为 Promise 在执行回调中都用 try catch 包裹起来了,其中所有的异常都被内部捕获到了,并未往上抛异常。

如下来自 Promises/A+ 的实现 then/promise 源码:

代码语言:javascript
复制
function getThen(obj) {
  try {
    return obj.then;
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

function tryCallOne(fn, a) {
  try {
    return fn(a);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}
function tryCallTwo(fn, a, b) {
  try {
    fn(a, b);
  } catch (ex) {
    LAST_ERROR = ex;
    return IS_ERROR;
  }
}

可以看到,这里执行 then (Promise.prototype.then 回调), tryCallTwo (doResolve 回调), tryCallOne (handleResolved 回调) 方法都被 try catch了。

异常都被包裹起来了。所以异常都不会被外层的 try catch 捕捉,因此在外层的 try catch 看来,Promise 根本没有异常,事实上也确实没有“异常”,比如:

代码语言:javascript
复制
try{
    new Promise(function (resolve, reject) {
        a.b;
    }).then(v=>{
        console.log(v);
    });
    console.log(111);
}catch(e){
    console.log('error',e);
}
console.log(222);
// output
111
222
Uncaught (in promise) ReferenceError: a is not defined

显然,a.b 报错之后的,111 和 222 都能正常运行,promise 的异常都已经被内部 catch 了,在外层的 try catch 看来就是没有异常,线程继续执行。

try catch 无法捕捉 Promise 的异常,是因为 Promise 的异常没有往上抛。

再看一例:

代码语言:javascript
复制
function a(){
    return new Promise((resolve, reject) =>{
        setTimeout(() => {
            reject(1);
        })
    })
}
try{
    await a();
}catch(e){
    console.log('error',e);
}
console.log(111);
//output
error 1
111

这个例子的异常被 catch 捕获到了,那么这里的 Promise 为啥能捕获到异常呢?

我们还是看开始的“一句话总结”

报错的时候(setTimeout 里面的 reject),线程执行已经进入 try catch 代码块,但是并未执行完成,这样的话当然可以捕获到异常。await 是将代码执行停留在 try catch 代码块里面。

敲黑板了:不要用 try catch 包裹 Promise , Promise 很强大,不用担心异常会往上抛!我们只需要给 Promise 增加 Promise.prototype.catch 就 OK 了

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端食堂 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 之前
  • 之中
  • 之后
  • 总结
  • Promise 没异常
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档