JavaScript高级程序设计读书笔记17

第17章 错误处理与调试

错误处理

try-catch语句

  • 把所有可能会抛出错误的代码都放在try语句快中,而把那些用于错误处理的代码放在catch块中
  • 错误信息有message属性和name属性
  • message属性是唯一一个能保证所有浏览器都支持的属性

finally

  • 只要代码中包含finally子句,则无论try或catch语句块中包含什么样的代码——甚至return语句,都不会阻止finally子句的执行。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function 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
    6
    function 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
    9
    function 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
    16
    function 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错误

  • 操作终止
  • 无效字符
  • 未找到成员
  • 未知运行时错误
  • 语法错误