Development
调试与错误恢复
系统化的根因调试指南。适用于测试失败、构建中断、行为不符合预期或遇到任何意外错误时。
系统化调试与结构化分类。当出现问题时,停止添加功能,按照结构化流程操作。
当出现任何意外情况时:
1. 停止添加功能或进行变更
2. 保留证据(错误输出、日志、重现步骤)
3. 使用分类清单进行诊断
4. 修复根本原因
5. 防止再次发生
6. 验证通过后才恢复
让失败可靠地发生。如果无法重现,就无法有信心地修复。
能否重现失败?
├── 是 → 进入第 2 步
└── 否
├── 收集更多上下文(日志、环境详情)
├── 尝试在最小环境中重现
└── 如果确实无法重现,记录条件并持续监控
缩小失败发生的位置:
哪个层出问题了?
├── UI/前端 → 检查控制台、DOM、网络面板
├── API/后端 → 检查服务器日志、请求/响应
├── 数据库 → 检查查询、数据模型、数据完整性
├── 构建工具 → 检查配置、依赖、环境
├── 外部服务 → 检查连通性、API 变更
└── 测试本身 → 检查测试是否正确
对回归 Bug 使用二分法:
git bisect start
git bisect bad # 当前提交有问题
git bisect good <known-good-sha> # 这个提交是正常的
git bisect run npm test -- --grep "failing test"
创建最小失败用例:
修复底层问题,而非症状:
症状:"用户列表显示重复条目"
症状修复(不好):
→ 在 UI 组件中去重:[...new Set(users)]
根本原因修复(好):
→ API 端点的 JOIN 查询产生了重复
→ 修复查询,添加 DISTINCT,或修复数据模型
不断追问:"为什么会这样?"直到找到根本原因。
编写一个捕获此特定失败的测试:
// Bug:包含特殊字符的任务标题破坏了搜索
it('finds tasks with special characters in title', async () => {
await createTask({ title: 'Fix "quotes" & <brackets>' });
const results = await searchTasks('quotes');
expect(results).toHaveLength(1);
expect(results[0].title).toBe('Fix "quotes" & <brackets>');
});
# 运行特定测试
npm test -- --grep "specific test"
# 运行完整测试套件
npm test
# 构建项目
npm run build
# 如适用,手动抽查
npm run dev
代码变更后测试失败:
├── 是否修改了测试覆盖的代码?
│ └── 是 → 检查是测试还是代码有问题
│ ├── 测试过时 → 更新测试
│ └── 代码有 Bug → 修复代码
├── 是否修改了不相关的代码?
│ └── 可能是副作用 → 检查共享状态
└── 测试原本就不稳定?
└── 检查时序问题、顺序依赖
构建失败:
├── 类型错误 → 阅读错误信息,检查类型
├── 导入错误 → 检查模块是否存在,导出是否匹配
├── 配置错误 → 检查构建配置文件
├── 依赖错误 → 检查 package.json,运行 npm install
└── 环境错误 → 检查 Node 版本、操作系统兼容性
运行时错误:
├── TypeError: Cannot read property 'x' of undefined
│ └── 某个不该为 null/undefined 的值为 null/undefined
├── 网络错误 / CORS
│ └── 检查 URL、请求头、服务器 CORS 配置
├── 渲染错误 / 白屏
│ └── 检查错误边界、控制台、组件树
└── 意外行为(无错误)
└── 在关键位置添加日志,逐步验证数据
// 安全默认值 + 警告(而非崩溃)
function getConfig(key: string): string {
const value = process.env[key];
if (!value) {
console.warn(`Missing config: ${key}, using default`);
return DEFAULTS[key] ?? '';
}
return value;
}
// 优雅降级(而非功能损坏)
function renderChart(data: ChartData[]) {
if (data.length === 0) {
return <EmptyState message="No data available" />;
}
try {
return <Chart data={data} />;
} catch (error) {
console.error('Chart render failed:', error);
return <ErrorState message="Unable to display chart" />;
}
}
修复 Bug 后: