onerror及Error对象

最近弄前端的错误信息统计,顺带再了解一遍错误的相关事件。

1 onerror事件

onerror(GlobalEventHandlers.onerror)事件是error事件的事件处理程序。针对各种目标的不同类型的错误触发了Error事件:

  • 当JavaScript运行错误时(包括语法错误)发生时,window会触发一个ErrorEvent接口的error事件,并执行window.onerror()。
  • 当一项资源(如<img><script>)加载失败,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()处理函数。这些error事件不会冒泡到window,不过能被单一的window.addEventListener捕获。

由于历史原因,window.onerror和element.onerror接受不同的参数。

window.onerror

语法:

1
2
3
window.onerror = function (message, source, lineno, colno, error) {
// ...
};

其中

  • message: String,错误信息。
  • source: String,发生错误的脚本URL。
  • lineno: Number,发生错误的行号。
  • colno: Number,发生错误的列号。
  • error:Error对象(后面会介绍)。

若该函数返回true,则阻止执行默认事件处理函数。

window.addEventListener(‘error’)

语法:

1
2
3
window.addEventListener('error', function (event) {
// ...
});

其中event包含有关事件和错误的所有信息。

element.onerror

语法:

1
2
3
element.onerror = function (event) {
// ...
};

其中event包含错误的所有信息。

解决onerror的跨域问题

由于浏览器的安全限制措施,当加载自不同域(协议、域名、端口三者任一不同)的脚本中发生错误时,为避免信息泄露,语法错误的细节将不会报告,代之的是返回”Script error.”

解决:

  • 相关的js文件上加上Access-Control-Allow-Origin: *的response header(必须)
  • 引用相关的js文件时加上crossorigin属性(必须)

2 Error对象

当运行时错误产生时,Error的实例对象会被抛出,此外通过Error的构造器也可以创建一个错误对象。

构建

语法:

1
new Error([message [, fileName [, lineNumber]]]);

其中

  • message:可阅读的错误描述信息。(可选)
  • fileName: 被创建的Error对象的fileName属性值。默认是调用Error构造器代码所在的文件的名字。(可选)
  • lineNumber: 被创建的Error对象的lineNumber属性值。默认是调用Error构造器代码所在的文件的行号。(可选)

其他

除了通用的Error构造函数外,JavaScript还有6个其他类型的错误构造函数。

  • EvalError、InternalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError

3 日志捕获

前端捕获异常分为全局捕获单点捕获。全局捕获代码集中,易于管理;单点捕获作为补充,对某些特殊情况进行捕获,但分散,不利于管理。

全局捕获

通过全局的接口,将捕获代码集中写在一个地方,可以利用的接口有:

  • window.addEventListener('error') / window.addEventListener('unhandledrejection') / document.addEventListener('click')
  • 框架级别的全局监听,例如aixos中使用interceptor进行拦截,vue、react都有自己的错误采集接口
  • 通过对全局函数进行封装包裹,实现在在调用该函数时自动捕获异常
  • 对实例方法重写(Patch),在原有功能基础上包裹一层,例如对console.error进行重写,在使用方法不变的情况下也可以异常捕获

单点捕获

在业务代码中对单个代码块进行包裹,或在逻辑流程中打点,实现有针对性的异常捕获:

  • try…catch
  • 专门写一个函数来收集异常信息,在异常发生时,调用该函数
  • 专门写一个函数来包裹其他函数,得到一个新函数,该新函数运行结果和原函数一模一样,只是在发生异常时可以捕获异常

跨域脚本异常

由于浏览器安全策略限制,跨域脚本报错时,无法直接获取错误的详细信息,只能得到一个Script Error。例如,我们会引入第三方依赖,或者将自己的脚本放在CDN时。

解决Script Error的方法:

方案一:

  • 将js内联到HTML中
  • 将js文件与HTML放在同域下

方案二:

  • 为页面上script标签添加crossorigin属性
  • 被引入脚本所在服务端响应头中,增加 Access-Control-Allow-Origin 来支持跨域资源共享

相关链接: