JavaScript 错误处理
在本教程中,您将学习如何在 JavaScript 中优雅地处理错误。
错误处理
有时您的 JavaScript 代码运行不如预期顺利,从而导致错误。 有许多可能导致错误的原因,例如:
- 网络连接问题
- 用户可能在表单字段中输入了无效值
- 引用不存在的对象或函数
- 向网络服务器发送或接收的数据不正确
- 应用程序需要访问的服务可能暂时不可用
这些类型的错误被称为运行时错误,因为它们发生在脚本运行时。专业的应用程序必须具有优雅地处理此类运行时错误的能力。通常这意味着更清楚、更准确地告知用户问题。
try...catch 语句
JavaScript 提供 try-catch
语句来捕获运行时错误,并优雅地处理它们。
任何可能抛出错误的代码都应该放在语句的try
块中,处理错误的代码放在catch
块中,如图所示:
// 可能导致错误的代码
} catch(error) {
// 发生错误时要执行的操作
}
如果在 try
块中的任何一点发生错误,代码执行会立即从 try
块转移到 catch
块。 如果 try
块中没有发生错误,则 catch
块将被忽略,程序将在 try-catch
语句之后继续执行。
以下示例演示了 try-catch
语句的实际工作方式:
try {
var greet = "Hi, there!";
document.write(greet);
// 试图访问一个不存在的变量
document.write(welcome);
// 如果发生错误,以下行将不会执行
alert("All statements are executed successfully.");
} catch(error) {
// 处理错误
alert("Caught error: " + error.message);
}
// 继续执行
document.write("<p>Hello World!</p>");
上面的脚本将生成一个错误并显示在警告对话框中,而不是将其打印到浏览器控制台。 除此之外,即使发生错误,程序也没有突然停止。
另外,请注意 catch
关键字后跟括号中的标识符。 这个标识符就像一个函数参数。 发生错误时,JavaScript 解释器会生成一个包含有关它的详细信息的对象。 然后这个错误对象作为参数传递给 catch
进行处理。
提示: try-catch
语句是一种异常处理机制。 异常是指示在程序执行期间发生某种异常情况或错误的信号。 术语"异常"和"错误"经常互换使用。
try...catch...finally 语句
try-catch
语句也可以有一个finally
子句。 finally
块中的代码将始终执行,无论 try
块中是否发生错误。
以下示例将始终显示完成代码执行所花费的总时间。
// Assigning the value returned by the prompt dialog box to a variable
var num = prompt("Enter a positive integer between 0 to 100");
// 存储执行开始的时间
var start = Date.now();
try {
if(num > 0 && num <= 100) {
alert(Math.pow(num, num)); // the base to the exponent power
} else {
throw new Error("An invalid value is entered!");
}
} catch(e) {
alert(e.message);
} finally {
// 显示执行代码所花费的时间
alert("Execution took: " + (Date.now() - start) + "ms");
}
抛出错误
到目前为止,我们已经看到了 JavaScript 解析器在发生错误时自动抛出的错误。 但是,也可以使用 throw
语句手动抛出错误。
throw
语句的一般形式(或语法)是:throw expression;
expression
表达式可以是对象或任何数据类型的值。 但是,最好使用对象,最好使用 name
和 message
属性。 JavaScript 内置的 Error()
构造函数提供了一种创建错误对象的便捷方式。 让我们看一些例子:
throw 123;
throw "Missing values!";
throw true;
throw { name: "InvalidParameter", message: "Parameter is not a number!" };
throw new Error("Something went wrong!");
注意: 如果您使用 JavaScript 内置的错误构造函数(例如 Error()
、TypeError()
等)来创建错误对象 ,则 name
属性与构造函数的名称相同,message
等于传递给构造函数的参数。
现在我们将创建一个函数 squareRoot()
来查找数字的平方根。 这可以通过使用 JavaScript 内置函数 Math.sqrt()
简单地完成,但这里的问题是,它返回 NaN
表示负数,而没有提供任何错误提示。
如果提供了负数,我们将通过引发自定义错误来解决此问题。
function squareRoot(number) {
// 如果数字为负,则抛出错误
if(number < 0) {
throw new Error("Sorry, can't calculate square root of a negative number.");
} else {
return Math.sqrt(number);
}
}
try {
squareRoot(16);
squareRoot(625);
squareRoot(-9);
squareRoot(100);
// 如果抛出错误,以下行将不会执行
alert("All calculations are performed successfully.");
} catch(e) {
// 处理错误
alert(e.message);
}
提示:理论上可以用虚数i
计算负数的平方根,其中i2 = -1
。 因此 -4
的平方根是 2i
,-9
的平方根是 3i
,以此类推。 但是 JavaScript 不支持虚数。
错误类型
Error
对象是所有错误的基本类型,它有两个主要属性 — name
属性指定错误的类型,message
属性保存更详细地描述错误的消息。 抛出的任何错误都将是 Error
对象的一个实例。
在 JavaScript 程序的执行过程中可能会出现几种不同类型的错误,例如 RangeError
、ReferenceError
、SyntaxError
、 TypeError
和 URIError
。
以下部分更详细地描述了这些错误类型中的每一种:
RangeError
当您使用超出允许值范围的数字时,会引发 RangeError
。 例如,创建一个负长度的数组会抛出 RangeError
。
var num = 12.735;
num.toFixed(200); // 抛出范围错误(允许范围从 0 到 100)
var array = new Array(-1); // 抛出范围错误
ReferenceError
当您尝试引用或访问不存在的变量或对象时,通常会抛出 ReferenceError
。 以下示例显示了 ReferenceError
是如何发生的。
var firstName = "Harry";
console.log(firstname); // 抛出引用错误(变量名区分大小写)
undefinedObj.getValues(); // 抛出引用错误
nonexistentArray.length; // 抛出引用错误
SyntaxError
如果您的 JavaScript 代码中存在任何语法问题,则会在运行时抛出 SyntaxError
。 例如,如果缺少右括号,则循环结构不正确,等等。
var array = ["a", "b", "c"];
document.write(array.slice(2); // 抛出语法错误(缺少括号)
alert("Hello World!'); // 抛出语法错误(引号不匹配)
TypeError
TypeError
当值不是预期类型时抛出。 例如,对数字调用字符串方法,对字符串调用数组方法等等。
var num = 123;
num.toLowerCase(); /* 抛出类型错误(因为 toLowerCase() 是一个字符串方法,数字不能转换为小写) */
var greet = "Hello World!"
greet.join() // 抛出类型错误(因为 join() 是一个数组方法)
URIError
当您为 URI 相关函数(例如 encodeURI()
或 decodeURI()
)指定了无效的 URI(代表 统一资源标识符)时,将引发 URIError
,如下所示:
var a = "%E6%A2%B";
decodeURI(a); // 抛出 URI 错误
var b = "\uD800";
encodeURI(b); // 抛出 URI 错误
注意:还有一种错误类型EvalError
,当通过 eval()
函数执行代码时发生错误时抛出。 但是,这个错误不再由 JavaScript 抛出,但是这个对象仍然是为了向后兼容。
也可以使用它们各自的构造函数和 throw
语句手动抛出特定的错误类型,例如,要抛出 TypeError
您可以使用 TypeError()
构造函数,如下所示:
var num = prompt("Please enter a number");
try {
if(num != "" && num !== null && isFinite(+num)) {
alert(Math.exp(num));
} else {
throw new TypeError("You have not entered a number.");
}
} catch(e) {
alert(e.name);
alert(e.message);
alert(e.stack); // non-standard property
}
注意: Error
对象还支持一些非标准属性。 最广泛使用的此类属性之一是:stack
,它返回该错误的堆栈跟踪。 您可以将其用于调试目的,但不要在生产站点上使用它。