本章内容
理解浏览器报告的错误
处理错误
调试 JavaScript 代码
错误处理
错误处理在程序设计中的重要性是一定的. 任何有影响力的 web 应用程序都需要一套完善的错误处理机制.
try-catch 语句
- try {// 可能会导致错误的代码} catch (e) {
- // 在错误发生时怎么处理
- }
错误类型
执行代码期间可能会发生的错误有多种类型. 每种错误都有对应的错误类型, 而当错误发生时, 就会抛出相应类型的错误对象.
ECMA-262 定义了下列 7 种错误类型:
- Error
- EvalError
- RangeError
- SyntaxError
- ReferenceError
- TypeError
- URIError
RangeError 类型的错误在数值超出相应范围时触发:
- try {
- let items1 = new Array(-20);
- var items2 = new Array(Number.MAX_VALUE);
- } catch (e) {
- console.dir(e)
- }
在找不到对象的情况下, 会发生 ReferenceError(这种情况下, 会直接导致人所共知的 "object expected" 浏览器错误). 通常, 在访问不存在的变量时, 就会发生这种错误:
- try {
- let obj = x;
- } catch (e) {
- console.dir(e)
- }
SyntaxError 类型, 当我们把语法错误的 JavaScript 字符串传入 eval() 函数时, 就会导致此类错误.
eval('a++ b')
TypeError 类型在 JavaScript 中会经常用到, 在变量中保存着意外的类型时, 或者在访问不存在的方法时, 都会导致这种错误. 错误的原因虽然多种多样.** 最常发生类型错误的情况, 就是传递给函数的参数事先未经检查, 结果传入类型与预期类型不相符.
Function.prototype.toString.call('name') // 抛出 typeError
在使用 encodeURI() 或 decodeURI(), 而 URI 格式不正确时, 就会导致 URIError 错误. 这种错误很少见, 因为前面说的这两个函数的容错性非常高.
利用不同错误类型, 可以获悉更多有关异常的信息, 从而有助于对错误作出恰当的处理.
- try {
- // ......
- } catch (e) {
- if (e instanceof TypeError) {
- // 处理类型错误
- } else if (e instanceof ReferenceError) {
- // 处理引用错误
- } else {
- // 处理其他类型的错误
- }
- }
在跨浏览器编程中, 检查错误类型是确定处理方式的最简便途径; 包含在 message 属性中的错误消息会因浏览器而异.
合理使用 try-catch
使用 try-catch 最适合处理那些我们无法控制的错误. 假设你在使用一个大型 JavaScript 库中的函数, 该函数可能会有意无意地抛出一些错误. 由于我们不能修改这个库的源代码, 所以大可将对该函数的调用放在 try-catch 语句当中.
抛出错误
与 try-catch 语句相配的还有一个 throw 操作符, 用于随时抛出自定义错误.
throw new Error('Something bad happend')
上面这行代码抛出一个通用错误, 带有一条自定义错误消息. 也可以像下面使用其他错误类型, 也可以模拟出类似的浏览器错误.
- throw new SyntaxError('I dont like your syntax');
- throw new TypeError('What type of variable do you take me for?');
- throw new RangeError('Sorry, you just dont have the range')
- throw new EvalError('That doesnt evaluate.')
- throw new URIError('Uri, is that you?');
- throw new ReferenceError('You didnt cite your references properly');
错误事件
- window.onerror = function (message, url, line) {
- // 处理错误
- }
处理错误的策略
略
常见的错误类型
错误处理的核心, 是首先要知道代码里会发生什么错误. 由于 JavaScript 是松散类型的, 而且也不验证函数的参数, 因此错误只会在代码运行期间出现. 一般需要关注三种错误:
类型转换错误
数据类型错误
通信错误
类型转换错误
全等操作符知道要比较的是两种不同的数据类型, 因而直接返回 false.
数据类型错误
Javascript 是松散类型的, 也就是说, 在使用变量和函数参数之前, 不会对它们进行比较以确保它们的数据类型正确.
通信错误
Javascript 与服务器之间的任何一次通信, 都有可能会产生错误.
第一种通信错误与格式不正确的 URL 或发送的数据有关. 最常见的问题是在将数据发送给服务器之前, 没有使用 encodeURIComponent() 对数据进行编码.
- function addQueryString(url, name, value) {
- if (url.indexOf('?') === -1) {
- url += '?';
- } else {
- url += '&';
- }
- url += `&${encodeURIComponent(name)} = ${encodeURIComponent(value)}`;
- return url;
- }
使用这个函数而不是手工构建 URL, 可以确保编码正确并避免相关错误.
区分致命错误和非致命错误
任何错误处理策略中最重要的一部分, 就是确定错误是否致命. 对于非致命错误, 可以根据下列一或多个条件来确定:
不影响用户的主要任务
只影响页面的一部分
可以恢复
重复相同操作可以消除错误
把错误记录到服务器
开发 Web 应用程序中的一种常见的做法, 就是集中保存错误日志, 以便查找重要错误的原因.
要建立这样一种 JavaScript 错误记录系统, 首先需要在服务器上创建一个页面, 用于处理错误数据. 这个页面的作用无非就是从查询字符中取得数据, 然后再将数据写入错误日志中. 这个页面可能会使用如下所示的函数:
- function logError (lev, msg) {
- let img = new Image();
- img.src = `log.php?e`
- }
这个 logError() 函数接收两个参数: 表示严重程度的数值或字符串及错误消息. 其中使用了 Image 对象来发送请求, 这样做非常灵活, 主要表现如下几方面:
所有浏览器都支持 Image 对象, 包括那些不支持 XMLHttpRequest 对象.
可以避免跨域限制.
在记录错误的过程中出问题的概率比较低. 大多数 Ajax 通信都是由 JavaScript 库提供的包装函数来处理的, 如果库代码本身有问题, 而你还在依赖该库记录错误, 可想而知, 错误消息是不可能得到记录的.
小结
错误处理至关重要. 不能提前预测到可能发生的错误, 不能提前采取恢复策略, 可能导致较差的用户体验.
下面是几种避免浏览器响应 JavaScript 错误的方法.
在可能发生错误的地方使用 try-catch 语句, 这样你还有机会以适当的方式对错误给出响应.
使用 window.onerror 事件处理程序, 这种方式可以接受 try-catch 不能处理的所有错误.
另外, 对任何 Web 应用程序都应该分析可能发生的错误. JavaScript 中发生错误的主要原因如下.
类型转换
未充分检测数据类型
发送给服务器或从服务器接收到的数据有错误
来源: https://juejin.im/post/5b1637f3e51d4506d33cf262