关于 error-handling
面向开发者的错误处理技能,提供 JavaScript 同步、异步及跨层错误处理约定,涵盖恢复、传播与进程退出。
主要功能
- 01区分编程错误与运行时错误
- 02处理同步和异步异常
- 03使用 DomainError 表达业务错误
- 04配置重试与进程级处理器
- 05支持优雅关闭
适用场景
- 01为 API 业务错误映射结构化代码
- 02为临时网络故障添加重试
- 03排查未捕获异常和未处理拒绝
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ metarhia/ metaskills --skill error-handling安装后在 Claude Code 中输入/error-handling确认已加载。
详细介绍
错误处理
错误分类
- 编程错误:缺陷(TypeError、ReferenceError、断言失败等)。修复代码;不要捕获后继续执行
- 运行时错误:预期会发生的失败(网络超时、文件未找到、输入无效等)。通过恢复、升级处理、通知用户或记录日志来妥善处理
同步错误处理
try {
const result = parse(input);
return result;
} catch (error) {
console.error({ error });
return defaultValue;
}
异步错误处理
try {
const data = await fetchData(url);
return data;
} catch (error) {
if (error.code === 'ECONNREFUSED') return fallback();
throw err;
}
DomainError
面向 API 层、包含错误代码的结构化业务错误:
({
method: async ({ email }) => {
const user = await domain.user.findByEmail(email);
if (!user) return new DomainError('ENOTFOUND');
return user;
},
errors: { ENOTFOUND: 'User not found' },
});
领域层抛出普通错误;必要时由 API 层将其转换为 DomainError。
跨层错误传播
domain throws Error → API catches → returns DomainError(code) → client gets structured error
不要向客户端暴露内部错误详情;将错误映射为已知错误代码或通用错误。
约定
- 区分编程错误和运行时错误;只对运行时错误进行恢复
- 在 API 方法中使用 DomainError 处理业务验证;编程缺陷应抛出错误
- 绝不静默吞掉错误;始终记录日志或向上传播
- 实现平稳关闭:停止接受连接,处理完现有连接并释放资源
- 对临时故障(网络、数据库连接)使用指数退避重试
- 始终在进程级别处理
uncaughtException和unhandledRejection
重试模式
const retry = async (fn, { attempts = 3, delay = 1000 } = {}) => {
for (let i = 0; i < attempts; i++) {
try {
return await fn();
} catch (err) {
if (i === attempts - 1) throw err;
await new Promise((r) => setTimeout(r, delay * (i + 1)));
}
}
};
进程级处理程序
process.on('uncaughtException', (error) => {
console.error('Uncaught:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection:', reason);
});
对于 uncaughtException,记录日志并退出(状态可能已损坏)。对于 unhandledRejection,记录日志并将其视为需要修复的缺陷。
平稳关闭
跟踪连接,并在退出前处理完所有连接:
const connections = new Map();
server.on('connection', (conn) => {
const res = null;
connections.set(conn, res);
conn.on('close', () => connections.delete(conn));
});
const shutdown = () => {
server.close(() => {
freeResources();
process.exit(0);
});
for (const [conn, res] of connections) {
if (res) res.end('Server shutting down');
conn.destroy();
}
};
process.on('SIGINT', shutdown);
process.on('SIGTERM', shutdown);
评论
支持 Markdown