# 错误处理
# Error
JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供Error
构造函数,所有抛出的错误都是这个构造函数的实例。
# 错误类型
JavaScript 语言标准只提到,Error
实例对象必须有message
属性,表示出错时的提示信息,没有提到其他属性。大多数 JavaScript 引擎,对Error
实例还提供name
和stack
属性,分别表示错误的名称和错误的堆栈。
- name Error 名称。例如,对于一个未定义的变量,名称是 "ReferenceError"。
- message 关于 error 的详细文字描述。
- stack 当前的调用栈。用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。
Error
实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他 6 种错误对象。也就是说,存在Error
的 6 个派生对象。
SyntaxError
对象是解析代码时发生的语法错误。ReferenceError
对象是引用一个不存在的变量时发生的错误。RangeError
对象是一个值超出有效范围时发生的错误。TypeError
对象是变量或参数不是预期类型时发生的错误。URIError
对象是 URI 相关函数的参数不正确时抛出的错误 。eval
函数没有被正确执行时,会抛出EvalError
错误。
它们的语法是:
let error = new Error(message);
// 或
let error = new SyntaxError(message);
let error = new ReferenceError(message);
// ...
# 自定义 Error
当我们在开发某些东西时,经常会需要我们自己的 error 类来反映在我们的任务中可能出错的特定任务。对于网络操作中的 error,我们需要 HttpError,对于数据库操作中的 error,我们需要 DbError,对于搜索操作中的 error,我们需要 NotFoundError,等等。
JavaScript 允许将 throw 与任何参数一起使用,所以从技术上讲,我们自定义的 error 不需要从 Error 中继承。但是,如果我们继承,那么就可以使用 obj instanceof Error 来识别 error 对象。因此,最好继承它。
# 扩展 Error
Error 类是内建的,但这是其近似代码,所以我们可以了解我们要扩展的内容:
// JavaScript 自身定义的内建的 Error 类的“伪代码”
class Error {
constructor(message) {
this.message = message;
this.name = "Error"; // (不同的内建 error 类有不同的名字)
this.stack = <call stack>; // 非标准的,但大多数环境都支持它
}
}
现在让我们从其中继承 ValidationError,并尝试进行运行。
class ValidationError extends Error {
constructor(message) {
super(message); // (1)
this.name = "ValidationError"; // (2)
}
}
function test() {
throw new ValidationError("Whoops!");
}
try {
test();
} catch (err) {
alert(err.message); // Whoops!
alert(err.name); // ValidationError
alert(err.stack); // 一个嵌套调用的列表,每个调用都有对应的行号
}
# throw 语句
throw
语句的作用是手动中断程序执行,抛出一个错误。
throw new SyntaxError("Incomplete data: no name"); // (*)
# try...catch 语句
一旦发生错误,程序就中止执行了。JavaScript 提供了try...catch
结构,允许对错误进行处理,选择是否往下执行。
try..catch 结构由两部分组成:try 和 catch:
try {
// 代码...
} catch (err) {
// 错误捕获
}
它按照以下步骤执行:
- 首先,执行 try {...} 中的代码。
- 如果这里没有错误,则忽略 catch(err):执行到 try 的末尾并跳过 catch 继续执行。
- 如果这里出现错误,则 try 执行停止,控制流转向 catch(err) 的开头。变量 err(我们可以使用任何名称)将包含一个 error 对象,该对象包含了所发生事件的详细信息。
try...catch
结构还允许在最后添加一个finally
代码块,表示不管是否出现错误,都必需在最后运行的语句。
# 错误收集
生产环境下的错误收集