JavaScript异常处理整理和思考

try-catch

try-catch 捕获异常的时候只可以捕获同步运行时的错误和异常,不能捕获语法错误和异步执行代码的错误和异常。javascript

try{
  // 同步代码出错
} catch(err) {
  // 捕获同步错误
}
复制代码

同步执行正常捕获

程序代码html

try {
    throw new Error('抛出异常')
} catch (err) {
    console.log("捕获到了异常"+err)
}
复制代码

执行结果前端

捕获到了异常Error: 抛出异常
复制代码

语法错误捕获不到

少写一个单引号,构造语法错误java

try {
    console.log('1)
} catch (err) {
    console.log("捕获到了异常"+err)
}
复制代码

执行结果node

console.log('1)
                ^^
SyntaxError: Invalid or unexpected token
复制代码

通常而言,编辑器会有语法检查,这个只是 try-catch 没法捕获的例子,实际中不多出现 git

异步错误捕获不到

使用 setTimeout 异步执行抛出错误github

try {
    setTimeout(()=>{
        throw new Error('异步错误')
    })
} catch (err) {
    console.log("捕获到了异常"+err)
}
复制代码

执行结果ajax

throw new Error('异步错误')
        ^

Error: 异步错误
    at Timeout.setTimeout [as _onTimeout] (D:\fcode\try-catch.js:7:15)
复制代码

思考

JavaScript代码执行的过程promise

  • 第一阶段:JS代码从入口处开始执行,此时会依照Run-to-completion 从头至尾执行同步代码,并将执行过程当中产生的异步任务添加到事件队列。
  • 第二阶段:同步代码执行完毕以后,经过事件循环检查事件队列执行此阶段产生的异步任务,每个异步任务执行期间又当作了一个新的同步任务的执行,如此循环。
  • try-catch 是同步执行代码,在第一阶段的时候执行完毕,异步错误或者异常是在第二阶段执行的,同步代码不可能执行它执行完之后的任务,因此捕获不到。
  • 异步任务的执行是脱离当前主线程的,只是一主线程共享内存和堆栈。(应该是吧,尚未具体考证)

promise中异常的捕获

promise 相比于 try-catch 更加容易捕获异步错误和异常。下面是一些注意点 浏览器

注意点

  • 直接经过return new Error('错误')的方式返回异常不能被下一个catch捕获到,这里返回的promiseresolve状态,会被传递下去被then捕获,只有throw new Error()才能被下一个catch捕获
var promise = new Promise((resolve, reject) => {
      resolve('1')
    })
    promise.then((data) => {
      return new Error('错误')
    }).catch((err) => {
      console.log('不会执行')
    }).then((data) => {
      console.log('打印以前返回的错误', data)
    })
    // 打印以前返回的错误 Error: 错误
    // at promise.then (4.html:16)
复制代码
  • then(success, error) then能够由两个处理函数,第一个用来处理resolved状态的promise返回值,第二个用来处理rejected状态的promise返回值,这里处理的是链式调用的返回的前一个promise
var promise = new Promise((resolve, reject) => {
    reject('错误')
  })
  promise.then((data)=>{
    console.log('不会执行,promise状态是rejected')
  }, (err)=>{
    // 捕获到错误
    console.log(err) // 错误
  }).catch((err) => {
    // 链式调用的前一个promise返回是一个resolve状态
    console.log('不能捕获到错误')
  })
复制代码
  • then中没有指定处理rejected状态的函数时,错误状态会一直传递下去直到被处理,要是没有处理不会被window捕获,直接控制台报错...
window.addEventListener('error', (e) => {
      console.log(e)
    })
    var promise = new Promise((resolve, reject) => {
      reject('错误')
    })
    promise.then((data)=>{
      console.log('未对错误处理')
    }).catch((err) => {
      // 执行
      console.log('上一个then中缺省处理错误的函数,错误会被封装成新的promise向下传递', err)
    })
    promise.then((data)=>{
      console.log('不处理,也没有后续,错误会被window捕捉到')
    })
复制代码
  • .then 的第二个处理错误的函数捕获不了第一个处理成功的函数抛出的错误,然后续的 .catch 能够捕获以前的错误
var promise = new Promise((resolve, rejected) => {
    resolve(1)
  })
  promise.then((data)=>{
    throw new Error('2')
  }, (err) => {
    console.log('不能捕获,then中第一个成功回调返回的错误')
  }).catch((err)=>{
    console.log('能够捕获上一个then中成功或者错误处理函数中抛出的错误')
  })
复制代码

解决方案

node中

process.on('uncaughtException', function (err) {
	// todo
});
复制代码

上述代码必定要加在最前面,当 Node 发现一个未捕获的异常时,会触发这个事件。可是在 uncaughtException 的回调事件中会丢失环境的上下文。

在浏览器中

当 JS 运行时错误发生时,window 会触发一个 ErrorEvent 接口的 error 事件,并执行 window.onerror()

window.onerror = function(msg, file, line, col, error) {
  // msg:错误信息(字符串)。
// file:发生错误的脚本URL(字符串)
// lineno:发生错误的行号(数字)
// col:发生错误的列号(数字)
// error:Error对象(对象)
  // todo
}
复制代码

当一项资源(如图片或脚本)加载失败,加载资源的元素会触发一个 Event 接口的 error 事件,并执行该元素上的onerror() 处理函数。这些 error 事件不会向上冒泡到 window 这样用 onerror() 没法捕捉到,此时可使用 window.addEventListener 捕获。

网络请求异常不是注册在DOM交互事件,不会向上冒泡,在事件的捕获阶段处理。

window.addEventListener('error', (error) => {
    console.log('捕获到异常:', error);
}, true)
复制代码

参考

除了 try-catch 和 promise 的场景还会有其余的一些异常处理,在平时接触和阅读文章的时候了解到还有

  • 静态资源(图片等)加载异常处理
  • ajax异步请求异常处理

这些实际遇到的较少,尚未太多的实战经验暂作记录,等有了经验以后再作补充。
参考文章以下:

相关文章
相关标签/搜索