01 · NOTES / WebGIS 开发
第 36 节 · 错误处理与调试
2026 年 9 月 1 日
第 36 节 · 错误处理与调试
📌 版本信息:基于 ECMAScript 2025 与 Chrome DevTools 现行版(2026-08-29 核对) 📚 来源:现代 JS 教程 · 错误处理 | MDN Error | Chrome DevTools 调试
一、这一节的目标
- 掌握 try/catch/finally 与 throw 的正确姿势
- 认全 JS 内置错误类型,看见报错就能归因
- 学会"读调用栈"——报错定位的系统方法
- 掌握 AI 协作时代的标准报错上报格式
- 熟练 console 调试全家桶与断点进阶
二、try/catch/finally
try {
riskyOperation(); // 可能炸的代码
} catch (err) {
// 只有这里能接住同步错误;err 是 Error 对象
console.error('失败了:', err.message);
// ⚠️ catch 块自己也可能再炸——里面也要小心
} finally {
closeDialog(); // 无论成败都执行(关 loading、释放资源)
}
三条纪律:
- 不要吞错:
catch (e) {}(空 catch)是"把火警铃拆了"——至少 console.error 留痕 - 只包必要的范围:大 try 包全函数 = 任何错误都被含糊处理;精确到"可能炸的那几行"
- 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?)
六、自测题
- 为什么
try { setTimeout(() => { throw … }) } catch {}接不到错误? Cannot read properties of undefined (reading 'lat')的排查第一步?- 优秀的 throw 信息包含哪三要素?
- 调用栈从上往下是"案发现场"还是"案发起点的上游"?点击行号会怎样?
- 想知道"是谁把我的图层 DOM 删了",用什么断点?
参考答案
- 异步回调的错误在未来的另一个"轮次"里抛出,try 块早已执行完毕;异步链要用 Promise.catch / await+try。
- 沿报错里的
.链从左向右找第一个可能为空的表达式(常见:fetch 结果、querySelector 结果、深层数据字段)。 - 发生了什么 + 收到的实际值 + 期望的格式。
- 最上面是案发现场(具体行),往下是调用它的上游;点击直达 DevTools 源码对应位置。
- DOM 变更断点(Break on → subtree/attribute modifications)。
七、下一步
调试体系成型 → 第 37 节:类型系统全解,TS 阶段二开篇。
TAGSweb