JavaScript脚本代码异常如何监听错误

4,895 阅读4分钟

本文参考前端代码异常监控
本文为2021届前端面试题目中腾讯面试题脚本如何全局检测错误的解答。

JS脚本代码异常主要分为两种情况:

  1. JS脚本里存在语法错误;
  2. JS脚本在运行时发生错误。

如果在一个脚本的代码里存在语法错误的话,这个脚本代码就不会继续运行,直接在控制台打印出语法错误。(PS:多个JS脚本的执行顺序又另当别论了,参加JavaScript语言运行机制之执行顺序

一般语法错误以及运行时错误浏览器都会在控制台里体现出错误信息以及出错的文件、行号、堆栈信息。

//打印未定义变量a
console.log(a)
//控制台输出
//这是一个ReferenceError(变量的问题)、a没有定义、在test.js文件的第7行
Uncaught ReferenceError: a is not defined at test.js:7 

想要去抓取这个错误,有两种方法:

  1. try catch。针对某个代码块使用try catch方法,这个代码块运行时出错能在catch里捕捉到。
  2. window.onerror。监听全局的error事件,能捕捉到语法错误和运行错误,同时还能知道出错的信息,以及出错的文件、行号、列号。

try catch

对代码块包裹try catch来抓取错误

try {
  console.log(a)
} catch (error) {
  console.log(error) //catch里的error即为控制台输出的错误
}

try catch的缺点:

  1. 没法捕捉try catch块的语法错误。出错后JS解释器不会执行当前的代码块,所以就没办法被catch
  2. 没法直接捕捉异步的错误事件。try catch只能捕获到同步代码的错误。

其实第二点的由来主要是try catch只能捕捉当前执行流的运行错误,异步回调对于try catch来说是不属于当前执行流,所以try catch不能一步到位捕捉异步。

try {
    var btn = document.getElementById('btn')
    btn.onclick = function(){
        console.log(a)
    }
} catch(error){
    console.log(error) //点击button后发现error没有输出,说明根本没有catch到错误
}

如何解决这个问题呢?——那就是异步回调内部编写try catch去捕获和处理。为了不让error混乱可以为每个try catch块编号。

try {
    var btn = document.getElementById('btn')
    btn.onclick = function(){
        try {
            console.log(a)
        } catch(e){
            console.log(`1 catch:${e}`//第一个catch
        }
        
    }
} catch(error){
    console.log(`2 catch: ${error}`//第二个catch
}

window.onerror

只要页面中出现脚本错误,就会产生 onerror 事件。所以全局环境下可以用window.onerror=function(e){...}或者window.addEventLinstener('error', function(e){...})监听错误。

window.onerror = function (msg, url, line, col, error) {
  console.log(msg) //转化为String形式的错误信息
  console.log(url) //发生错误的脚本url
  console.log(line) //错误在哪一行
  console.log(col) //错误发生的列号
  console.log(error) //完整的错误信息
  return true //表示不把错误信息打印到控制台
}
console.log(a)

window.onerror能捕捉到语法错误,但是语法出错的代码块不能跟window.onerror在同一个块。因为同一个代码块,代码发生语法错误根本就不会运行。所以需要将window.onerror分离,并且比其他脚本先执行即可捕捉到语法错误。

//分离到<head>里执行,就能够比其他脚本先执行
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script>
    window.onerror = function (msg, url, line, col, error) {
      console.log(msg) //转化为String形式的错误信息
      console.log(url) //发生错误的脚本url
      console.log(line) //错误在哪一行
      console.log(col) //错误发生的列号
      console.log(error) //完整的错误信息
      return true //表示不把错误信息打印到控制台
    }
  </script>
</head>
<body>
      <!-- error事件已经在前面执行形成全局监听,所以能够捕捉到test.js里的语法错误 -->
      <script src='test.js'><script> 
</body>
</html>
但是window.onerror存在一个问题就是捕捉到错误后并不能像try catch一样能够让代码正常运行下去,代码在出错部分抛出错误就暂停运行了。 所以基本还是会使用try catch去catch错误,window.onerror可以用来做错误统计上报。