2020-9-8日:错误处理与调试

  • try-catch语句 ;

基本语法:

try{     
    // 可能会导致错误的代码 
} catch(error){     
    // 在错误发生时怎么处理 
} 
try {     
    window.someNonexistentFunction();     
} catch (error){     
    alert(error.message); // 错误对象的 message 属性;
} 

 

  • try-catch语句 的finally子句 ;

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

  1. try-catch 语句的每一部分都放了一条 return 语句
  2. 表面上看,调用这个函数会返 回 2,因为返回 2的 return 语句位于 try 语句块中,而执行该语句又不会出错;
  3. 由于后还有 一个 finally 子句,结果就会导致该 return 语句被忽略
  4. 函数只能返回 0;
  5. 只要代码中包含 finally 子句,那么无论 try 还是 catch 语句块 中的 return 语句都将被忽略;

 

function testFinally(){     
    try {         
        return 2;     
    } catch (error){        
        return 1;     
    } finally {         
        return 0;     
    } 
} 

 

 

  • 不同的错误类型;

 Error  :是基类型,其他错误类型都继承自该类型;

 EvalError: 没有把 eval()当成函数调用,就会抛出错误;

 RangeError

 ReferenceError

 SyntaxError

 TypeError

 URIError

使用 instanceof 操作符:判断错误的类型;

try {     
    someFunction(); 
} catch (error){     
    if (error instanceof TypeError){         
        /处理类型错误     
    } else if (error instanceof ReferenceError){        
         //处理引用错误     
    } else {         
        //处理其他类型的错误     
    } 
} 

建议:

假设你在使用一个大型 JavaScript 库中的 函数,该函数可能会有意无意地抛出一些错误。由于我们不能修改这个库的源代码,所以大可将对该函 数的调用放在 try-catch 语句当中,万一有什么错误发生,也好恰当地处理它们;

 

  •  throw 操作符:随时抛出自定义错误 ;

作用:随时抛出自定义错误;

要求:必须 要给 throw 操作符指定一个值,这个值是什么类型,没有要求

throw 12345; 
throw "Hello world!"; 
throw true; 
throw { name: "JavaScript"}; 

遇到 throw 操作符时,代码会立即停止执行。仅当有 try-catch 语句捕获到被抛出的值时,代 码才会继续执行;

例子:

自执行函数:

(function myFunction() {
            try {
                var x = 120;
                if (x == "") throw "empty";
                if (x > 10) throw "too high"; // x= 120; 抛出异常错误:too high;   
                if (x < 5) throw "too low";
            }
            catch (err) {
                console.log(err)              //catch()捕捉错误,返回值err为抛出的自定义异常错‘ too high’
} })();

 

 

  • 使用某种内置错误类型,可以更真实地模拟浏览器错误 ; 

代码抛出了一个通用错误,带有一条自定义错误消息。

throw new Error("Something bad happened."); // 每种错误类型的构造函数接收一个参 数,即实际的错误消息  --"Something bad happened.";

 

  • 利用原型链:继承 Error 来创建自定义错误类型;

简例:

 

function CustomError(message){     
    this.name = "CustomError";     
    this.message = message; 
} 

CustomError.prototype = new Error();

throw new CustomError("My message"); 

 

浏览器对待继承自 Error 的自定义错误类型,就像对待其他错误类型一样;

IE:只有在抛出 Error 对象的时候才会显示自定义错误消息。对于其他类型,它 都无一例外地显示"exception thrown and not caught"(抛出了异常,且未被 捕获);

 

  •  抛出错误的时机 ;针对函数为什么会执行失败给出更多信息,抛出自定义错误是一种很方便的方式;

简例:

 values 参数不是数组,就会抛出一个错误;错误消息中包含了函数 的名称,以及为什么会发生错误的明确描述

function process(values) {
        if (!(values instanceof Array)) { 
            throw new Error("process(): Argument must be an array."); 
            }
        values.sort(); 
        for (var i = 0, len = values.length; i < len; i++) { 
            if (values[i] > 100) { 
                return values[i]; 
            } 
        } 
        return -1;
    }

 

 

  • window 对象的 error 事件;
  1. 任何没有通过 try-catch 处理的错误都会触发 ;
  2. 指定 onerror 事件处理程序,必须使用如下所示的 DOM0级技术,它没有遵循“DOM2级 事件”的标准格式;
  3. window.onerror = function(message, url, line){         
    alert(message); 
    }; 

     

  4. 返回 false,可以阻止浏览器报告错误的默认行;
    window.onerror = function(message, url, line){     // onerror 事件处理程序都不会创建 event 对象, 但它可以接收三个参数:错误消息、错误所在的 URL 和代码行号;一般主要是错误信息有用;
        alert(message);     
        return false; 
    }; 

    返回 false,这个函数实际上就充当了整个文档中的 try-catch 语句;

 

图像也支持 error 事件;

   src 特性中的 URL不能返回可以被识别的图像格式,就会触 发 error 事件; 

var image = new Image(); 
EventUtil.addHandler(image, "load", function(event){     
    alert("Image loaded!"); 
}); 
EventUtil.addHandler(image, "error", function(event){     
    alert("Image not loaded!"); 
}); 
image.src = "smilex.gif"; //指定不存在的文件 

 

  1. 加载图像失败时就会显示一个警告框 ;
  2. 发生 error 事件时,图 像下载过程已经结束,也就是说不能再重新下载了 ;

 

  • 常见的错误类型

 类型转换错误

 数据类型错误

 通信错误 :

                  1. 第一种通信错误与格式不正确的 URL 或发送的数据有关;  没有使用 encodeURIComponent()对数据进行编码。

http://www.yourdomain.com/?redir=http://www.someotherdomain.com?a=b&c=d 

针对"redir="后面的所有字符串调用 encodeURIComponent()就可以解决这个问题,结果将产生 如下字符串:

http://www.yourdomain.com/?redir=http%3A%2F%2Fwww.someotherdomain.com%3Fa%3Db%26c%3Dd

对于查询字符串,应该记住必须要使用 encodeURIComponent()方法;

定义一个处理查询字符串的函数,

function addQueryStringArg(url, name, value) {
        if (url.indexOf("?") == -1) { 
            url += "?"; // 传入的 URL不包含问 号,还要给它添加问号;
        } else { 
            url += "&"; // 否则,就要添加一个和号;
        }
        url += encodeURIComponent(name) + "=" + encodeURIComponent(value); return url;
    }

使用:

var url = "http://www.somedomain.com";
var newUrl = addQueryStringArg(url, "redir", "http://www.someotherdomain.com?a=b&c=d");
alert(newUrl);

另外:服务器响应的数据不正确时,也会发生通信错误;

  • 致命错误和非致命错误 ;

例子:

for (var i=0, len=mods.length; i < len; i++){     
    mods[i].init(); //可能会导致致命错误 
} 

依次对每个模块调用 init()方法;

问题在于:

    任何模块的 init() 方法如果出错,都会导致数组中后续的所有模块无法再进行初始化;

修改:

错误变成非致命; 捕捉错误;

for (var i=0, len=mods.length; i < len; i++){    
    try {         
        mods[i].init();     
    } catch (ex) {         
        //在这里处理错误   ;例如:跳过当前模块继续初始化等  
    } 
}    

 

assert()函数抛出: 自定义的错误; 减少抛出错误所需的代码量,

  参数(2个): 一个是求值结果应该为 true 的条件,另一个是条件为 false 时要抛出的错误;

  作用: 代替某些函数中需要调试的 if 语句,以便输出错误消息;

  

定义:

function assert(condition, message) {
        if (!condition) {
            throw new Error(message);
        }
    }

使用:

function divide(num1, num2) {
        assert(typeof num1 == "number" && typeof num2 == "number", "divide(): Both arguments must be numbers.");
        return num1 / num2;
    } 

 

posted @ 2020-09-08 17:29  Amber丶Li  阅读(121)  评论(0)    收藏  举报