返回笔记列表
01 · NOTES / WebGIS 开发

第 36 节 · 错误处理与调试

2026 年 9 月 1 日

第 36 节 · 错误处理与调试

📌 版本信息:基于 ECMAScript 2025 与 Chrome DevTools 现行版(2026-08-29 核对) 📚 来源:现代 JS 教程 · 错误处理MDN ErrorChrome DevTools 调试

一、这一节的目标

  1. 掌握 try/catch/finally 与 throw 的正确姿势
  2. 认全 JS 内置错误类型,看见报错就能归因
  3. 学会"读调用栈"——报错定位的系统方法
  4. 掌握 AI 协作时代的标准报错上报格式
  5. 熟练 console 调试全家桶与断点进阶

二、try/catch/finally

try {
  riskyOperation();          // 可能炸的代码
} catch (err) {
  // 只有这里能接住同步错误;err 是 Error 对象
  console.error('失败了:', err.message);
  // ⚠️ catch 块自己也可能再炸——里面也要小心
} finally {
  closeDialog();             // 无论成败都执行(关 loading、释放资源)
}

三条纪律:

  1. 不要吞错catch (e) {}(空 catch)是"把火警铃拆了"——至少 console.error 留痕
  2. 只包必要的范围:大 try 包全函数 = 任何错误都被含糊处理;精确到"可能炸的那几行"
  3. catch 异步必须配套await 在 try 里能被 catch(第 17 节的模式);回调风格的错误 catch 不到(setTimeout(() => { throw … }) 直接逃逸到全局)
// 主动抛错:把"业务上不可能"变成明确失败
function parseBbox(str) {
  const nums = str.split(',').map(Number);
  if (nums.length !== 4 || nums.some((n) => Number.isNaN(n))) {
    throw new Error(`bbox 格式错误:"${str}",应为 "minLng,minLat,maxLng,maxLat"`);
  }
  return nums;
}
// ✅ 抛错信息要包含:发生了什么 + 收到了什么 + 期望什么

三、内置错误类型:见名知因

类型 触发场景 例子
TypeError 对 undefined/null 取属性;调用非函数 Cannot read properties of undefined (reading 'x')
ReferenceError 变量不存在(未声明/作用域外) foo is not defined
SyntaxError 语法写错(编译期) 括号不配对、JSON 格式错
RangeError 值超范围 new Array(-1)、栈溢出 Maximum call stack size exceeded
URIError encode/decodeURI 非法参数 少见

见报错第一反应:TypeError → 查"谁可能是 undefined/null"(沿 . 链从左到右);ReferenceError → 查拼写与作用域;栈溢出 → 查无限递归。

自定义错误(业务项目规范):

class ApiError extends Error {
  constructor(message, status) {
    super(message);
    this.name = 'ApiError';
    this.status = status;        // 携带 HTTP 状态码,上层按码分流处理
  }
}

四、读调用栈(Stack Trace)

function renderMap() { loadTiles(); }
function loadTiles() { JSON.parse('{bad json}'); }
// ❌ Uncaught SyntaxError: Unexpected token b in JSON at position 1
//     at JSON.parse (<anonymous>)
//     at loadTiles (main.js:12:24)   ← 由下往上读!
//     at renderMap (main.js:8:20)

读法:最下面是"案发起点"(用户动作/入口),最上面是"案发现场"(具体那行)。中间每行 = 文件:行:列,点击直达源码。异步栈里还会看到 async 标注与 Promise 链路。

AI 上报模板(存进肌肉记忆):

1. 我想做什么:在地图上加载 GeoJSON 图层
2. 完整报错(含文件行号):TypeError: Cannot read properties of undefined (reading 'features') at main.js:47
3. 相关代码片段(报错行 ±10 行)
4. 我试过什么:确认 fetch 返回 200

五、console 全家桶与断点进阶

console.log/warn/error      // 常规三件套
console.table(arrayOfObjects) // 表格视图——看 GeoJSON properties 数组神器
console.group('瓦片加载')     // 折叠分组
console.time('parse'); … console.timeEnd('parse');   // 计时(性能初查)
console.assert(x > 0, 'x 应为正数');  // 条件不满足才输出
console.trace('到这了');     // 打印当前调用栈

断点进阶(Sources 面板):

  • 条件断点:右键行号 → Add conditional breakpoint → id === 42(只在特定数据时停)
  • Logpoint(日志点):不暂停只打印——调试循环数据时的"无侵入 console.log"
  • DOM 变更断点:Elements → 右键元素 → Break on → subtree modifications(谁改了我的 DOM?)

六、自测题

  1. 为什么 try { setTimeout(() => { throw … }) } catch {} 接不到错误?
  2. Cannot read properties of undefined (reading 'lat') 的排查第一步?
  3. 优秀的 throw 信息包含哪三要素?
  4. 调用栈从上往下是"案发现场"还是"案发起点的上游"?点击行号会怎样?
  5. 想知道"是谁把我的图层 DOM 删了",用什么断点?

参考答案

  1. 异步回调的错误在未来的另一个"轮次"里抛出,try 块早已执行完毕;异步链要用 Promise.catch / await+try。
  2. 沿报错里的 . 链从左向右找第一个可能为空的表达式(常见:fetch 结果、querySelector 结果、深层数据字段)。
  3. 发生了什么 + 收到的实际值 + 期望的格式。
  4. 最上面是案发现场(具体行),往下是调用它的上游;点击直达 DevTools 源码对应位置。
  5. DOM 变更断点(Break on → subtree/attribute modifications)。

七、下一步

调试体系成型 → 第 37 节:类型系统全解,TS 阶段二开篇。

TAGSweb