错误处理与调试

至于抛出错误与捕获错误的区别,可以这样想:应该只在确切知道接下来该做什么的时候捕获错 误。捕获错误的目的是阻止浏览器以其默认方式响应;抛出错误的目的是为错误提供有关其发生原因的 说明。

把错误记录到服务器中

Web 应用程序开发中的一个常见做法是建立中心化的错误日志存储和跟踪系统。数据库和服务器错 误正常写到日志中并按照常用 API 加以分类。对复杂的 Web 应用程序而言,最好也把 JavaScript 错误发送回服务器记录下来。这样做可以把错误记录到与服务器相同的系统,只要把它们归类到前端错误即可。 使用相同的系统可以进行相同的分析,而不用考虑错误来源。 要建立 JavaScript 错误日志系统,首先需要在服务器上有页面或入口可以处理错误数据。该页面只 26 要从查询字符串中取得错误数据,然后把它们保存到错误日志中即可。比如,该页面可以使用如下代码:

function logError(sev, msg) {
  let img = new Image(),
  encodedSev = encodeURIComponent(sev),
  encodedMsg = encodeURIComponent(msg);
  img.src = 'log.php?sev=${encodedSev}&msg=${encodedMsg}';
}

logError()函数接收两个参数:严重程度和错误消息。严重程度可以是数值或字符串,具体取决 于使用的日志系统。这里使用 Image 对象发送请求主要是从灵活性方面考虑的。

  • 所有浏览器都支持 Image 对象,即使不支持 XMLHttpRequest 对象也一样。

  • 不受跨域规则限制。通常,接收错误消息的应该是多个服务器中的一个,而 XMLHttpRequest 此时就比较麻烦。

  • 记录错误的过程很少出错。大多数 Ajax 通信借助 JavaScript 库的包装来处理。如果这个库本身 出错,而你又要利用它记录错误,那么显然错误消息永远不会发给服务器。 只要是使用 try/catch 语句的地方,都可以把相关错误记录下来。下面是一个例子:

for (let mod of mods){
  try {
    mod.init();
  } catch (ex){
    logError("nonfatal", 'Module init failed: ${ex.message}');
  }
}

在这个例子中,模块初始化失败就会调用 logError()函数。第一个参数是表示错误严重程度的 "nonfatal",第二个参数在上下文信息后面追加了 JavaScript 错误消息。记录到服务器的错误消息应 该包含尽量多的上下文信息,以便找出错误的确切原因。

抛出错误

在大型应用程序中,自定义错误通常使用 assert()函数抛出错误。这个函数接收一个应该为 true 的条件,并在条件为 false 时抛出错误。下面是一个基本的 assert()函数:

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

这个 assert()函数可用于代替多个 if 语句,同时也是记录错误的好地方。下面的代码演示了如 何使用它:

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

相比于之前的例子,使用 assert()函数可以减少抛出自定义错误所需的代码量,并且让代码更好 理解。

Last updated