浏览器 "Script error"

先看浏览器中的错误:

Error: foobar
    at new bar (:241:11)
    at foo (:245:5)
    at callFunction (:229:33)
    at Object.InjectedScript._evaluateOn (:875:140)
    at Object.InjectedScript._evaluateAndWrap (:808:34)

以上的报错是不是很熟悉,就是我们经常在浏览器开发者工具的console板块里见到的,可以清楚的看到报错的文件还有位置。这种报错是怎么发生的?又是如何可以定位的?

首先介绍下“Script error”。
“Script error.”是因为错误源来自不同域的Js文件时,浏览器发送到onerror回调的内容。onerror是一个特殊的浏览器事件,只要抛出未捕获的JavaScript错误就会触发该事件。这是记录客户端错误并将其报告给服务器的最简单方法之一。

window.onerror = function (msg, url, lineNo, columnNo, error) {
  // ... handle error ...

  return false;
}

函数参数:

  • msg: 错误信息
  • url: 发生错误的脚本url
  • lineno: 发生错误的行号
  • colno: 发生错误的列号
  • error: Error对象
    Error对象的非标准属性Error.prototype.stack是最有价值的,告诉了错误发生的位置。

举例:




  example.com/test


  
  


// another-domain.com/app.js

function foo() {
  bar(); // ReferenceError: bar is not a function
}

以上例子会输出如下, 未显示具体错误的原因是因为浏览器为了保护不同源的脚本文件。

"Script error.", "", 0, 0, undefined

那如何得到这些错误的具体信息呢?两种方案:

方案一 CORS属性和headers

  1. script标签添加crossorigin=”anonymous”, 浏览器不会将任何潜在的用户识别信息(如Cookie)等传输到服务器。

  1. 设置Access-Control-Allow-Origin

Access-Control-Allow-Origin: https://www.example.com

方案二 try/catch

  1. 将代码包裹在try/catch中捕获错误,因为该错误对象包含在每个现代浏览器的堆栈属性中。
    例如:
function invoke(obj, method, args) {
  try {
    return obj[method].apply(this, args);
  } catch (e) {
    captureError(e); // report the error
    throw e; // re-throw the error
  }
}

invoke(Math, 'highest', [1, 2]); // throws error, no method Math.highest
  1. 当然,手动在每个函数里都去做try/catch太麻烦,可以写一个util,在每个新的JS栈开始的地方调用。具体在以下地方调用:
  • 在程序开始的地方 (e.g. jQuery中 $(document).ready)
  • 在事件处理函数中, e.g. addEventListener 或 $.fn.click
  • 基于计时器的回调, e.g. setTimeout 或 requestAnimationFrame
$(wrapErrors(function () { // application start
  doSynchronousStuff1(); // doesn't need to be wrapped

  setTimeout(wrapErrors(function () {
    doSynchronousStuff2(); // doesn't need to be wrapped
  });

  $('.foo').click(wrapErrors(function () {
    doSynchronousStuff3(); // doesn't need to be wrapped
  });
}));

获取具体的错误之后,可能还需要将错误上报到服务器,举个简单的例子:

function captureError(ex) {
  var errorData = {
    name: ex.name, // e.g. ReferenceError
    message: ex.line, // e.g. x is undefined
    url: document.location.href,
    stack: ex.stack // stacktrace string; remember, different per-browser!
  };

  $.post('/logger/js/', {
    data: errorData
  });
}

尽管浏览器基本都实现了window.onerror,但是每个浏览器实现的方式不同,特别是onerror lisener的参数个数和参数结构不同。

当然,以上是两种比较简单的方法,如果不麻烦的话还是推荐设置CORS和header方法。也有一些工具自动帮你用try-catch包裹代码,也会尝试去捕获跨域的js错误信息,例如sentry js.

参考:
https://blog.sentry.io/2016/05/17/what-is-script-error
https://developer.mozilla.org/zh-CN/docs/Web/API/GlobalEventHandlers/onerror

你可能感兴趣的:(js)