最近一直在跟进前端异常监控系统的开发,有一些心得要记录下,希望对大家有一点点帮助。
区分异常和错误
我们经常在讲的错误,其实应该是广义的错误,它包括了异常(Exception)与错误(Error)。本文中的错误指的是侠义的程序错误,与异常区别开来;我们在开发阶段和测试阶段会发生一些显而易见的问题导致流程或者用户界面出现问题,脚本错误是比较严重的问题,会导致用户流程终止,导致页面程序无法响应等等,这种一般属于程序错误。
除此之外,还有一些由于客户端的环境千差万别,有很多异常我们在开发阶段和测试阶段很难发现,或者说是只有在特定的环境才能发生的程序主流程之外的错误,我姑且称为异常。
下面是找的一段比较专业的描述:
程序中的异常(Exception)是指发生在程序执行过程中非频繁非正常的事件,它位于程序正常流程之外。
异常大致可分为两类:
- 硬件异常:由CPU发起,它们可能是某些指令序列的执行导致的。比如除零或访问非法内存地址等。
- 软件异常:由应用程序或操作系统显式发起。例如系统可以检测到指定的参数非法值。
编程语言中的异常则属于软件异常。
而程序中的错误(Error),通常是指发生在程序执行过程中正常的事件,它就在程序正常流程范围之内。
所以简单总结一下:程序中的错误 发生在程序执行过程中的普遍事件,程序异常是指执行过程中非频繁非正常的个案。
由于异常的偶发性,我们在开发测试阶段也未必能复现到,所以需要借助用户侧的日志监控来发现。
我最近整理了一下监控系统的日志,发现一些比较常见的异常或错误。有一些也是我们开发中经常会发生的,现在记录下来总结下巩固一下。
原生错误
SyntaxError对象:
在控制台输入如下代码,你会发现有如下的异常提示,这些都属于原生错误类型
var 01 Uncaught SyntaxError: Unexpected number var 0a Uncaught SyntaxError: Invalid or unexpected token console.log 'hello'); Uncaught SyntaxError: Unexpected string; Uncaught SyntaxError: Unexpected token u in JSON at position 0 JSON格式不对
Uncaught SyntaxError: Unexpected number => 表示意外的数字,用数字开头的变量不符合语法
Uncaught SyntaxError: Invalid or unexpected token => token非法,表示:未被发现的语法错误:无效或意外的标志。
Uncaught SyntaxError: Unexpected string; 字符串不符合要求
上面代码的错误,都是在语法解析阶段就可以发现,所以会抛出SyntaxError。
JSON的异常如下:
const _texrta = function(){ return new Promise(resolve=>{ setTimeout(()=>{ return resolve('aaa') },200)} ) } function ssss() { return _texrta().then(JSON.parse) };ssss()
Uncaught (in promise) SyntaxError: Unexpected token a in JSON at position 0 -> JSON对象格式错误
ReferenceError对象
ReferenceError对象是引用一个不存在的变量时发生的错误:
1、使用未定义的的变量,变量不存在或者找不到变量
比如下面
Uncaught ReferenceError: APP is not defined
ReferenceError: Can’t find variable: on_page_disappear
2、另一种触发场景是,将一个值分配给无法分配的对象,比如对函数的运行结果或者this赋值
this = a
Uncaught SyntaxError: Invalid left-hand side in assignment
TypeError 对象
TypeError对象是变量或参数不是预期类型时发生的错误。比如,对字符串、布尔值、数值等原始类型的值使用new命令,就会抛出这种错误,因为new命令的参数应该是一个构造函数。
这个类型的异常也是很常见的:
var s; s.default:Uncaught TypeError: Cannot read property ‘default’ of undefined //读取了一个没定义的变量的default
Object.keys(aaa):Uncaught TypeError: Cannot convert undefined or null to object //不可用将undefined或者null 转化为对象,可能是类似Object.keys(),Object.assign()等方法中传错变量是null或者undefined
Uncaught TypeError: Cannot read property ‘offsetWidth’ of undefined //读取了一个没定义的变量的属性offsetWidth,同1
TypeError: undefined is not an object (evaluating ‘window.external.OnDocumentReady’) // 可能 未定义(的external.OnDocumentReady)不是一个对象;
TypeError: window.__$_qihoo360_$__.dayMode is not a function // window.__$_qihoo360_$__.dayMode 不是一个function
Uncaught TypeError: Object [object global] has no method ‘BestpayReceiveFromNative’ // 对象没有对应的方法或属性
下面三个类型的异常:RangeError,URIError,EvalError比较少发现,也了解一下:
RangeError 对象
RangeError对象
是一个值超出有效范围时发生的错误。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,第三是函数堆栈超过最大值比如调用一个不终止的递归函数。
new Array(-1)
// Uncaught RangeError: Invalid array length
1.01.toFixed(-1)
Uncaught RangeError: toFixed() digits argument must be between 0 and 100
另第三种情况:函数堆栈超过最大值比如调用一个不终止的递归函数
Uncaught RangeError: Maximum call stack
URIError 对象
URIError对象
是 URI 相关函数的参数不正确时抛出的错误,主要涉及encodeURI()
、decodeURI()
、encodeURIComponent()
、decodeURIComponent()
、escape()
和unescape()
这六个函数。Uncaught URIError: URI malformed
EvalError 对象
eval函数没有被正确执行时,会抛出EvalError
错误。该错误类型已经不再使用了,只是为了保证与以前代码兼容,才继续保留。
最后就是我们最熟悉的Error对象
Error 实例对象
JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供Error
构造函数,所有抛出的错误都是这个构造函数的实例。
new Error(‘出错了’);
Error: 出错了
Error
构造函数接受一个参数,表示错误提示,可以从实例的message
属性读到这个参数。抛出Error
实例对象以后,整个程序就中断在发生错误的地方,不再往下执行。
JavaScript 语言标准只提到,Error
实例对象必须有message
属性,表示出错时的提示信息,没有提到其他属性。
大多数 JavaScript 引擎,对Error
实例还提供name
和stack
属性,分别表示错误的名称和错误的堆栈,但它们是非标准的,不是每种实现都有。
总结:以上这6种派生错误,连同原始的Error
对象,都是构造函数。我们可以使用它们,手动生成错误对象的实例。这些构造函数都接受一个参数,代表错误提示信息(message
)
还有其他异常场景,欢迎补充。