近日腾讯音乐电话面试提到如何监控前端代码报错,涉及 js 代码报错,异步报错,图片资源、js资源加载报错,Promise报错如何进行监控统计,答的不够全面,于是仔细研究下。

 

  1. js 代码报错
  2. 异步报错
  3. 图片请求报错
  4. script src 资源加载报错
  5. Promise reject 或者 抛错

 

JS 异常处理

使用 try...catch...

try {
  w
}catch(e){
  console.log(e) // ReferenceError: w is not defined
}

异步处理

对于异步报错,使用try catch是无法捕捉到错误的,因为异步事件已经放入事件队列中,无法捕捉到。

于是可以采用在异步回调函数里面进行 try catch,如果有若干个异步事件都要进行 try catch就会比较繁琐,后面会介绍。

try {
  setTimeout(() => {
    err
  }, 10);
} catch (error) {
  console.log(error); // 并不会打印
}

前端异常监控_编程

 

图片请求

针对单个图片请求报错可以调用 Image 对象提供的api onerror回调函数进行错误捕获,那如果是很多图片呢?或者是其他的资源请求不到呢?

const img = new Image();
img.src = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png";
img.onload = () => {
  document.body.appendChild(img);
};
img.onerror = () => {
  document.body.appendChild(new Text("Could not load the nebula :("));
};

 

Promise异常处理

通过 Promise 可以帮助我们解决异步回调地狱的问题,但是一旦 Promise 实例抛出异常而你没有用 catch 去捕获的话,onerror 或 try-catch 也无能为力,无法捕捉到错误,像如下示例报错:

Promise.reject('promise error');
new Promise((resolve, reject) => {
  reject('promise error');
});
new Promise((resolve) => {
  resolve();
}).then(() => {
  throw 'promise error'
});

可以使用 window.addEventListener  unhandledrejection  事件

 

MDN:

Promise 被 reject 且没有 reject 处理器的时候,会触发 unhandledrejection 事件

window.addEventListener("unhandledrejection", event => {
  console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`);
  // Prevent the default handling (such as outputting the error to the console
  event.preventDefault(); 
});

Promise.reject('promise error');
new Promise((resolve, reject) => {
  reject('promise error');
});
new Promise((resolve) => {
  resolve();
}).then(() => {
  throw 'promise error'
});

前端异常监控_java_02

全局异常捕获 window.onerror

 

 

MDN上是这么介绍的

 

  • JavaScript运行时错误(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()
  • 当一项资源(如<img><script>加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会向上冒泡到window,不过(至少在Firefox中)能被单一的window.addEventListener捕获。
  • 若该函数返回true,则阻止执行默认事件处理函数(window.addEventListener('error', function(event) { ... }))
window.onerror = function (msg, url, lineNo, columnNo, error) {
    var string = msg.toLowerCase();
    var substring = "script error";
    if (string.indexOf(substring) > -1){
        alert('Script Error: See Browser Console for Detail');
    } else {
        var message = [
            'Message: ' + msg,
            'URL: ' + url,
            'Line: ' + lineNo,
            'Column: ' + columnNo,
            'Error object: ' + JSON.stringify(error)
        ].join(' - ');

        alert(message);
    }

    return false;
};

error

前端异常监控_工程化管理_03

 

需要注意的是:

  1. window.onerror 事件必须写在代码运行之前,如果 写在执行代码之后,JS 代码执行报错了,就不会继续捕获到 window.onerror 事件了。
  2. window.onerror 是无法捕获到网络异常的错误

 

也可以通过 window.addEventListener('error') 进行捕获错误。

 

如下示例请求图片资源失败,由于网络请求异常不会事件冒泡,因此必须在捕获阶段将其捕捉到才行,于是window.addEventListener 设置为 true 在捕获阶段进行

  <img src="./1.png">
  <img src="./2.png">
  <img src="./3.png">
  <img src="./4.png">
  <script>
    window.addEventListener('error', (event) => {
      console.log(
        event
      );
    }, true);
  </script>

前端异常监控_java_04

js 资源加载失败也同图片一样,错误事件监听事件要提前。

<script>
    window.addEventListener('error', (event) => {
      console.log(
        event
      );
    }, true);
  </script>
  <script src="12.js"></script>

 

特别的,如果 A 网站使用 B(CDN) 域名下的js资源,但是JS执行报错了,浏览器只会给出 Script error 错误提示,不会有具体报错信息,原因是:浏览器的同源策略限制。

 

为了能够将CDN的报错信息显示出来,可以做如下操作:

1、A网站的服务端配置:Access-Control-Allow-Origin: b.com

2、A网站前端配置如下:

// http://a.com/index.html
<script>
  window.onerror = function (error) {
    console.log(error)
    return true
  };
</script>
<script src="http://b.com/test.js" crossorigin></script>

 

更强悍的前端异常监控可以看下 Sentry