# 错误处理

# Error

JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供Error构造函数,所有抛出的错误都是这个构造函数的实例。

# 错误类型

JavaScript 语言标准只提到,Error实例对象必须有message属性,表示出错时的提示信息,没有提到其他属性。大多数 JavaScript 引擎,对Error实例还提供namestack属性,分别表示错误的名称和错误的堆栈。

  • name Error 名称。例如,对于一个未定义的变量,名称是 "ReferenceError"。
  • message 关于 error 的详细文字描述。
  • stack 当前的调用栈。用于调试目的的一个字符串,其中包含有关导致 error 的嵌套调用序列的信息。

Error实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他 6 种错误对象。也就是说,存在Error的 6 个派生对象。

  1. SyntaxError对象是解析代码时发生的语法错误。
  2. ReferenceError对象是引用一个不存在的变量时发生的错误。
  3. RangeError对象是一个值超出有效范围时发生的错误。
  4. TypeError对象是变量或参数不是预期类型时发生的错误。
  5. URIError对象是 URI 相关函数的参数不正确时抛出的错误 。
  6. 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代码块,表示不管是否出现错误,都必需在最后运行的语句。

# 错误收集

生产环境下的错误收集