浏览器 "Script error"

先看浏览器中的错误:

Error: foobar
    at new bar (<anonymous>:241:11)
    at foo (<anonymous>:245:5)
    at callFunction (<anonymous>:229:33)
    at Object.InjectedScript._evaluateOn (<anonymous>:875:140)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>: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是最有价值的,告诉了错误发生的位置。

举例:

<!doctype html>
<html>
<head>
  <title>example.com/test</title>
</head>
<body>
  <script src="http://another-domain.com/app.js"></script>
  <script>
  window.onerror = function (message, url, line, column, error) {
    console.log(message, url, line, column, error);
  }
  foo(); // call function declared in app.js
  </script>
</body>
</html>
// 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)等传输到服务器。

<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>

  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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值