在前端项目中,由于JavaScript本身是一个弱类型语言,加上浏览器环境的复杂性,网络问题等等,很容易发生错误。做好网页错误监控,不断优化代码,提高代码健壮性是一项很重要的工作。
JS中的Error
通用Error
Error有两个标准属性:
Error.prototype.name
:错误的名字Error.prototype.message
:错误的描述
一个标准方法:
Error.prototype.toString
:返回表示一个表示错误的字符串
非标准的属性(各个浏览器厂商对于Error都有自己的实现)。比如下面这些属性:
Error.prototype.fileName
:产生错误的文件名。Error.prototype.lineNumber
:产生错误的行号。Error.prototype.columnNumber
:产生错误的列号。Error.prototype.stack
:堆栈信息。这个比较常用。
Error种类
除了通用的Error构造函数外,JavaScript还有7个其他类型的错误构造函数。
- InternalError: 创建一个代表Javascript引擎内部错误的异常抛出的实例。 如: “递归太多”。非ECMAScript标准。
- RangeError: 数值变量或参数超出其有效范围。例子:
var a = new Array(-1);
- EvalError: 与
eval()
相关的错误。eval()
本身没有正确执行。 - ReferenceError: 引用错误。 例子:
console.log(b);
- SyntaxError: 语法错误。例子:
var a = ;
- TypeError: 变量或参数不属于有效范围。例子:
[1,2].split('.')
- URIError: 给
encodeURI
或decodeURl()
传递的参数无效。例子:decodeURI('%2')
当JavaScript运行过程中出错时,会抛出上8种(上述7种加上通用错误类型)错误中的其中一种错误。错误类型可以通过error.name
拿到。
DOMException
除了JavaScript本身运行时会发生的错误。页面中还会有其他的异常,比如错误地操作了DOM。
DOMException有以下三个属性:
DOMException.code
:错误编号。DOMException.message
:错误描述。DOMException.name
:错误名称。
Promise产生的异常
在Promise中,如果Promise被reject了,就会抛出异常:PromiseRejectionEvent。下面两种情况都会导致Promise被reject:
- 业务代码本身调用了
Promise.reject
。 - Promise中的代码出错。
PromiseRejectionEvent的构造函数目前在浏览器中大多都不兼容,这里就不说了。
PromiseRejectionEvent的属性有两个:
PromiseRejectionEvent.promise
:被reject的Promise。PromiseRejectionEvent.reason
:Promise被reject的原因。会传递给reject。Promise的catch中的参数。
捕获错误
window.onerror
当有JS运行时错误触发时,window会触发error事件,并执行window.onerror()
。
1 | window.onerror = function(message, source, lineno, colno, error) { ... } |
函数参数:
- message:错误信息(字符串)。可用于HTML onerror=””处理程序中的event。
- source:发生错误的脚本URL(字符串)
- lineno:发生错误的行号(数字)
- colno:发生错误的列号(数字)
- error:Error对象
若该函数返回true,则阻止执行默认事件处理函数,如异常信息不会在console中打印。没有返回值或者返回值为false的时候,异常信息会在console中打印。
window.addEventListener('error')
1 | window.addEventListener('error', function(event) { ... }) |
event是ErrorEvent对象的实例。ErrorEvent是事件对象在脚本发生错误时产生,从Event继承而来。由于是事件,自然可以拿到target属性。ErrorEvent还包括了错误发生时的信息:
ErrorEvent.prototype.message
: 字符串,包含了所发生错误的描述信息。ErrorEvent.prototype.filename
: 字符串,包含了发生错误的脚本文件的文件名。ErrorEvent.prototype.lineno
: 数字,包含了错误发生时所在的行号。ErrorEvent.prototype.colno
: 数字,包含了错误发生时所在的列号。ErrorEvent.prototype.error
: 发生错误时所抛出的 Error 对象。
捕获未处理的Promise错误-window.addEventListener('unhandledrejection')
在使用Promise的时候,如果没有声明catch代码块,Promise的异常会被抛出。我们可以通过监听unhandledrejection事件或者window.onunhandledrejection
捕获到该异常。
1 | window.addEventListener('unhandledrejection', function (event) { ... }); |
event就是上文提到的PromiseRejectionEvent,我们只需要关注其reason(Promise的reject值)就行。
例如:
1 | window.addEventListener('unhandledrejection', event => { |
例如:
当一个Promise错误最初未被处理,但是稍后又得到了处理,则会触发rejectionhandled事件:
1 | window.addEventListener('unhandledrejection', event => { |
window.onerror
和window.addEventListener('error')
的区别
事件监听器和事件处理器的区别。监听器只能声明一次,后续的声明会覆盖之前的声明。而事件处理器则可以绑定多个回调函数。
资源(
<img>
或<script>
)加载失败时,加载资源的元素会触发一个Event接口的error事件,并执行该元素上的onerror()
处理函数。但这些error事件不会向上冒泡到window。不过,这些error事件能被window.addEventListener('error')
捕获。也就是说,面对资源加载失败的错误,只能用window.addEventListerner('error')
,window.onerror
无效。
实际应用
页面错误监控:
1 | // JS错误处理 |