第17章 错误处理与调试
错误处理
try-catch语句
- 把所有可能会抛出错误的代码都放在try语句快中,而把那些用于错误处理的代码放在catch块中
- 错误信息有message属性和name属性
- message属性是唯一一个能保证所有浏览器都支持的属性
finally
只要代码中包含finally子句,则无论try或catch语句块中包含什么样的代码——甚至return语句,都不会阻止finally子句的执行。
1
2
3
4
5
6
7
8
9function testFinally() {
try {
return 2;
} catch (error) {
return 1;
} finally {
return 0;
}
}调用这个函数只能返回0
错误类型
- 每种错误都有对应的错误类型,而当错误发生时,就会抛出相应类型的错误对象。
- Error:Error是基类型,其他错误类型都继承自该类型
- EvalError:在使用eval()函数而发生异常时抛出
- RangeError:数值超出相应范围时触发
- ReferenceError:在找不到对象的情况下,会发生ReferenceError
- SyntaxError:当我们把语法错误的JavaScript字符串传入eval()函数时,就会导致此类错误
- TypeError:执行特定于类型的操作时,变量的类型并不符合要求所致。最常发生类型错误的情况,就是传递给函数的参数事先未经检查,结果传入类型与预期类型不相符。
- URIError:URI格式不正确时,就会导致URIError错误
合理使用try-catch
- 当try-catch语句中发生错误时,浏览器会认为错误已经被处理了。因而不会通过前面讨论的机制记录或报告错误。
- 使用try-catch最适合处理那些我们无法控制的错误.
- 在明明白白地知道自己的代码会发生错误时,不应该使用try-catch语句。
抛出错误
- throw操作符,用于随时抛出自定义错误。
- 在遇到throw操作符时,代码会立即停止执行。仅当有try-catch语句捕获到被抛出的值时,代码才会继续执行。
- 通过使用某种内置错误类型,可以更真实地模拟浏览器错误。每种错误类型的构造函数接受一个参数,即实际的错误信息。
利用原型链还可以通过继承Error来创建自定义错误类型。此时,需要为新创建的错误类型指定name和message属性。
1
2
3
4
5
6function CustomError(message){
this.name = "CustomError";
this.message = message;
}
CustomError.prototype = new Error();
throw new CustomError("My message");想知道函数为什么执行失败,抛出自定义错误是一种很方便的方式。
- 应该捕获那些你确切知道该如何处理的错误。
- 捕获错误的目的在于避免浏览器以默认方式处理他们;而抛出错误的目的在于提供错误发生具体原因的消息。
错误(error)事件
- 任何没有通过try-catch处理的错误都会触发window对象的error事件。
- 在事件处理程序中返回false,可以阻止浏览器报告错误的默认行为,实际充当了整个文档中的try-catch语句,可以捕获所有无代码处理的运行时错误。
处理错误的策略
- 作为开发者,必须知道代码何时可能出错,出什么错,还要有一套错误跟踪问题的系统。
常见的错误类型
- 常见的错误类型:类型转换错误、数据类型错误、通信错误
类型转换错误
- 由于相等和不相等操作符会在比较之前进行一个转换,所以js会误以为这个比较是正确的而继续执行代码,然后导致错误,所以建议使用全等或不全等
- 在流程控制语句中使用非布尔值为条件很容易导致类型转换错误。
数据类型错误
- 在流程控制语句中使用非布尔值为条件很容易导致数据类型错误
- 另一种错误做法,就是只针对要使用的某一个特性执行特性检测
- 关于数据类型错误,大体上来说,基本类型的值应该使用typeof来洁厕,而对象的值应该使用instanceof来检测。
通信错误
- 最常见的错误:将数据发送给服务器之前,没有使用encodeURIComponent()对数据进行编码
- 在服务器响应的数据不正确时,也可能发生通信错误
区分致命错误和非致命错误
- 非致命错误:不影响用户的主要任务、只影响页面的一部分、可以恢复、重复相同错误可以消除错误
- 致命错误:程序无法继续运行、明显影响到用户的主要操作、会导致其他连带错误
把错误记录到服务器
- 首先要在服务器创建一个页面,用于处理错误数据。
- 只要是使用try-catch语句,就应该把响应错误记录到日志中
调试技术
将消息记录到控制台
- 通过console对象向JavaScript控制台写入信息。
1
2
3
4
5
6
7
8
9function log(message){
if (typeof console == "object"){
console.log(message);
} else if (typeof opera == "object"){
opera.postError(message);
} else if (typeof java == "object" && typeof java.lang == "object"){
java.lang.System.out.println(message);
}
}
将消息记录到当前页面
- 在页面中开辟一小块区域,用以显示消息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function log(message){
var console = document.getElementById("debuginfo");
if(console ===null){
console = document.createElement("div");
console.id = "debuginfo";
console.style.background = "#dedede";
console.style.border = "1px solid silver";
console.style.padding = "5px";
console.style.width = "400px";
console.style.position = "absolute";
console.style.right = "0px";
console.style.top = "0px";
document.body.appendChild(console);
}
console.innerHTML += "<p>" + message + "</p>";
}
抛出错误
- 如果错误消息很具体,基本上就可以把它当作确定错误来源的依据
- 这种错误消息必须能够明确给出导致错误的原因,才能省去其他调试操作
- 对于大型的应用程序来说,自定义的错误通常使用assert()函数抛出
常见的IE错误
- 操作终止
- 无效字符
- 未找到成员
- 未知运行时错误
- 语法错误