JavaScript try-catch statement (error handling)

The importance of error handling in handler design is unquestionable, and any impactful web application needs a comprehensive set of error handling mechanisms. Of course, most of the best out there do it, but usually only server-side applications can do it. In practice, server-side teams tend to put a lot of effort into error handling mechanisms, often thinking about categorizing errors by type, frequency, or other important criteria. This allows developers to understand the problems users may have with their applications when using simple database queries or report generation scripts.

While error handling for client applications is equally important, it has only been in the last few years that it has really been taken seriously. In fact, we have to face the indisputable fact that the vast majority of people who use the web are not technically savvy, and many of them don't even know what a browser is, let alone let them say which one they prefer. Each browser behaves more or less differently when a JavaScript error occurs. Some will display small icons, and some will not move at all. These default behaviors of browsers for JavaScript errors are irregular to end users. In the best case, the user encounters an error and can't figure out why, and they try to redo it again, in the worst case, the user becomes angry and never returns. A good error handling mechanism allows users to be alerted in time to know exactly what happened, so they don't panic. To do this, as developers, we must understand what tools and tools are available when dealing with JavaScript errors.

One, try-catch statement

ECMA-262 version 3 introduced the try-catch statement as a standard way of handling exceptions in JavaScript. The basic syntax is shown below, and it is obvious that this is exactly the same as the try-catch statement in Java:

try {
     // code that may cause an error 
} catch (error) {
     // what to do when an error occurs 
}

 That is, we should put all the code that might throw an error in the try statement block, and put the code for error handling in the catch block , for example:

try {
    window.someNonexistentFunction(); // Call a nonexistent function 
} catch (error) {
    alert('An error happened!');
}

 If an error occurs in any code in the try block, the execution of the code is immediately exited, followed by the execution of the catch block , which receives an object containing the error message. Unlike in other languages, give the error object a name even if you don't want to use it . The actual information contained in this object will vary from browser to browser, but in common there is a message property that holds the error message. ECMA-262 also specifies a name attribute that holds the wrong type, which is currently supported by all browsers (versions prior to Opera 9 do not support this attribute). Therefore, in the event of an error, it is possible to realistically display the information given by the browser like this:

try {
    window.someNonexistentFunction(); // Call a nonexistent function 
} catch (error) {
    alert(error.message);
}

 This example uses the message property of the error object when displaying the error message to the user. This message property is the only property that is guaranteed to be supported by all browsers . In addition, IE, Firefox, Safari, Chrome and Opera are all Additional relevant information is added to the event object. IE adds the exact same description property as the message property, plus a number property that holds the number of internal errors. Firefox adds fileName, lineNumber, and stack (containing stack trace information) properties. Safari adds line (representing line number), sourceId (representing internal error code), and sourceUrl properties. Of course, when programming across browsers, it's best to just use the message property.

1, finally clause

Although optional in a try-catch statement, once the finally clause is used, its code is executed anyway . In other words, if the code in the try block is executed normally, the finally clause will be executed; if the catch block is executed due to an error, the finally clause will still be executed. As long as the code contains a finally clause, no matter what code is contained in the try or catch block—even the return statement—will not prevent the finally clause from executing . Take a look at the following function:

复制代码
function testFinally() {
    try {
        return 2;
    } catch (error) {
        return 1;
    } finally {
        return 0;
    }
}

testFinally(); //0
复制代码

 这个函数在try-catch语句的每一部分都放了一条return语句。表面上看,调用这个函数会返回2,因为返回2个return语句位于try语句块中,而执行该语句又不会出错。可是,由于最后还有一个finally子句,结果就会导致该return语句被忽略,也就是说,调用这个函数只能返回0,如果把finally子句拿掉,这个函数将返回2.(请读者务必要记住,只要代码中包含finally子句,那么无论try还是catch语句块中的return语句都将被忽略。因此,在使用finally子句之前,一定要非常清楚你想要代码怎么样)

2,错误类型

执行代码期间可能会发生的错误有多种类型,每种错误都有对应的错误类型,而当错误发生时,就会抛出相应类型的错误对象。ECMA-262定义了下列7种错误类型:

01, Error

02, EvalError

03, RangeError

04, ReferenceError

05, SyntaxError

06, TypeError

07, URIError

其中,Error是基类型其他错误类型都继承自该类型,因此,所有错误类型共享了一组相同的属性(错误对象中的方法全是默认的对象方法)。Error类型的错误很少见,如果有也是浏览器抛出的;这个基类型的主要目的是供开发人员抛出自定义错误

EvalError类型的错误是在使用eval()函数而发生异常时抛出。ECMA-262中对这个错误有如下描述:“表示全局函数eval的使用方式与其定义不相符。“除此之外,并没有救到底什么情况会引发这种错误给出说明。在实际开发中碰到这种错误的可能性并不大。

RangeError类型的错误会在数值超出相应范围时触发。例如,在定义数组时,如果指定了数组不支持的项数(如-20或Number.MAX_VALUE),就会触发这种错误。下面是具体的例子:

var items1 = new Array(-20); //VM77:1 Uncaught RangeError: Invalid array length(…)
var items2 = new Array(Number.MAX_VALUE); //VM79:1 Uncaught RangeError: Invalid array length(…)

JavaScript中经常会出现这种范围错误。

在找不到对象的情况下,会发生ReferenceError(这种情况下,会直接导致人所共知的“object expected"浏览器错误)。通常,在访问不存在的变量时,就会发生这种错误,例如:

 var obj = x; //VM112:1 Uncaught ReferenceError: x is not defined(…) 在x未声明的情况下抛出ReferenceError

至于SyntaxError,当我们把语法错误的JavaScript字符串传入eval()函数时,就会导致此类错误,例如:

 eval('a ++ b'); //VM114:1 Uncaught SyntaxError: Unexpected identifier(…)

 如果语法错误的代码出现在eval()函数之外,则不太可能发生SyntaxError,因为此时的语法错误导致JavaScript代码立即停止执行。

TypeError类型在JavaScript中经常用到,在变量中保存着意外的类型时,或者在访问不存在的方法时,都会导致这种错误。错误的原因虽然多种多样,但归根结底还是由于在执行特定于类型的操作时,变量的类型并不符合要求所致。下面来看几个例子:

最常发生类型错误的情况,就是传递给函数的参数事先未经检查,结果传入类型与预期类型不相符。

在使用encodeURI()或decodeURI(),而URI格式不正确时,就会导致URIError错误,这种错误也很少见,因为前面说的这两个函数的容错性非常高。

利用不同的错误类型,可以熟悉更多有关异常的信息,从而有助于对错误作出恰当的处理,要想知道错误的类型,可以像下面这样在try-catch语句的catch语句中使用instanceof操作符:

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

 在跨浏览器编程中,检查错误类型是确定处理方式的最简便途径,包含在message属性中的错误消息会因浏览器而异。

3,善用try-catch

当try-catch语句中发生错误时,浏览器会认为错误已经被处理了。因而不会通过前面讨论的机制记录或报告错误。对于那些不要求用户懂技术,也不需要用户理解错误的Web应用程序,这应该说是个理想的结果。不过,try-catch能够让我们实现自己的错误处理机制。

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

在明明白白地知道自己的代码会发生错误时,再使用try-catch语句就不太合适了。例如,如果传递给函数的参数是字符串而非数值,就会造成函数出错,那么就应该先检查函数的类型,然后再决定如果去做。在这种情况下,不应该使用try-catch语句。

4,try-catch语句执行顺序

看下面的例子:

执行顺序为:首先执行try语句块中的代码,如果抛出异常,接着执行catch语句块中代码,如果没有异常,catch语句块中代码将会被忽略,但不管是否有异常,最后最会执行finally子句。try后面必须接着一个catch或者finally,也就是说JavaScript中的try-catch可以有3中组合形式。即try-catch、try-finally、try-catch-finally三种形式。

try-catch一般的应用场景大家都比较熟悉,下面来看几个嵌套的例子:

上面这个例子中,最外部的try语句块中嵌套了一个try-finally语句,内部的try语句中抛出了一个异常,但是内部没有catch语句块,所以会执行最近的一个catch语句块,但是在跳出外部try包含语句块之前,需要先执行内部的finally语句块中的代码,所以最后的结果如上图所示。再看一个例子:

这个例子中,内部嵌套的语句块中有catch语句,所以当内部try语句块中抛出异常时,会接着执行内部的catch语句块,然后执行finally子句。由于异常已经在内部处理完成,所以外部的catch语句块会被忽略,所以最终结果如上所示。再看一个例子:

这个例子在上面例子的基础上,内部的catch语句块中又抛出了一个异常,所以,在执行完相应语句后,会接着执行外部的catch语句,结果如上所示。

 二, 抛出错误

与try-catch语句相配的还有一个throw操作符,用于随时抛出自定义错误。抛出错误时,必须要给throw操作符指定一个值。这个值是什么类型,没有要求。下列代码都是有效的。

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

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

通过使用某种内置错误类型,可以更真实地模拟浏览器错误。每种错误类型的构造函数接受一个参数,即实际的错误信息。下面是一个例子:

throw new Error('Something bad happened.');

 

这行代码抛出了一个通用错误,带有一条自定义错误信息。浏览器会像处理自己生成的错误一样,来处理这行代码抛出的错误。换句话说,浏览器会以常规方式报告这一错误,并且会显示这里的自定义错误类型。像下面使用其他错误类型,也可以模拟出类似的浏览器错误:

复制代码
throw new SyntaxError("I don't like your syntax.");
throw new TypeError("what type of variable do you take me for?");
throw new RangeError("Sorry, you just don't have the range.");
throw new EvalError("That doesn't evaluate.");
throw new URIError("Uri, is that you?");
throw new ReferenceError("You didn't cite your references properly.");
复制代码

 在创建自定义错误消息时,最常用的错误类型是Error、RangeError、ReferenceError和TypeError。另外,利用原型链还可以通过继承Error来创建自定义错误类型。此时,需要为新创建的错误类型指定name和message属性。来看一个例子:

浏览器对待继承自Error的自定义错误类型,就像对待其他错误类型一样。如果要捕获自己抛出的错误并且把它与浏览器错误区别对待的话,创建自定义错误是很有用的。IE只有在抛出Error对象的时候才会显示自定义错误信息。对于其他类型,它都无一例外地显示"exception thrown and not caught"(抛出了异常,且未被捕获))。


您可能感兴趣的:

  1. 详解1000+项目数据分析出来的10大JavaScript错误
  2. 10个用Console来Debug的高级技巧
  3. 有浏览器的地方就有Fundebug
  4. Debug前端HTML/CSS

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325603196&siteId=291194637