讲解

程序出错有两种姿态:默默给出一个错误值(如 NaN、undefined),或者抛出异常中断执行。JavaScript 用 throw 抛出异常——任何值都能被抛,但约定抛 Error 对象(或其子类),因为它带有 message 和 stack(调用栈)信息。抛出后执行立即中止,沿调用栈向上找最近的 try...catch,找不到就崩溃(浏览器控制台红字、Node 进程退出)。

try...catch...finally 是处理结构:try 里放可能出错的代码,catch 捕获并拿到错误对象,finally 无论成败都执行(适合释放资源、关加载动画)。内置错误类型有 TypeError(类型不对)、ReferenceError(变量不存在)、RangeError(数值越界)、SyntaxError(语法错误)等;自定义错误用 class MyError extends Error,配合 instanceof 区分错误种类做不同处理。

错误处理的工程原则:在「知道该怎么办」的层级捕获(给用户提示、重试、降级),不知道怎么办就让它继续向上抛;catch 里不要静默吞错(空 catch 块是万恶之源),至少记日志;主动对入参做校验并尽早抛出明确的错误(fail fast),比在深处炸出一行看不懂的 TypeError 友好得多。异步错误(Promise 的 reject)要用 .catch 或 async 里的 try/catch 接住,后面的章节会展开。

示例

// 抛出与捕获
function divide(a, b) {
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new TypeError('参数必须是数字');
  }
  if (b === 0) {
    throw new RangeError('除数不能为 0');
  }
  return a / b;
}

try {
  console.log(divide(10, 2));
  console.log(divide(10, 0)); // 抛出,下面那行不会执行
  console.log('这行不会执行');
} catch (e) {
  console.log('捕获:', e.constructor.name, '-', e.message);
} finally {
  console.log('finally:无论成败都执行');
}

// 自定义错误 + instanceof 分类处理
class NetworkError extends Error {
  constructor(url) {
    super('网络请求失败:' + url);
    this.name = 'NetworkError';
  }
}

function handle(error) {
  if (error instanceof NetworkError) {
    return '提示用户检查网络';
  }
  if (error instanceof TypeError) {
    return '记录 bug 上报';
  }
  return '未知错误,继续抛出';
}
console.log(handle(new NetworkError('/api/user')));
console.log(handle(new TypeError('x is not a function')));

// Error 对象的 stack 帮助定位
const err = new Error('演示');
console.log('有 message:', err.message, ',stack 存在:', typeof err.stack === 'string');

常见坑

  • 空 catch 吞错:catch (e) {} 让 bug 完全隐身,是代码评审的一票否决项。至少 console.error 留痕。
  • throw 字符串:throw '出错了' 丢失了堆栈信息,调试时无从定位。永远 throw new Error(...)。
  • catch 不到异步回调里的错误:try 包住 setTimeout 的外层没用——回调执行时 try 早已结束。异步错误要在异步内部捕获(Promise 链上 .catch)。
  • finally 里 return 覆盖一切:finally 中的 return 会覆盖 try/catch 里的返回值和未抛出的异常,几乎总是 bug,别在 finally 里 return。

小结

throw 抛 Error 对象,try/catch/finally 捕获与收尾;自定义错误类 + instanceof 分类处理;不吞错、尽早抛、在能处理的层级捕获。下一节了解让错误更早暴露的严格模式。