用专门的类、放置得当的捕获边界,以及一个充分发挥潜力的 console,构建一套明确的错误策略。
在 Kodokon 中打开本课健壮性不在于捕获每一个错误,而在于在正确的地方捕获它们。实战准则:尽可能贴近 bug 之处,快速而响亮地失败(校验、不变量),并且只在你真正能够作出反应的边界处捕获:显示一条消息、重试、记录日志。一个什么有用的事都不做的 try/catch 并不会让代码更安全;它只会让失败变得悄无声息。
function parseConfig(json) {
try {
return JSON.parse(json);
} catch (error) {
console.error("Unreadable config:", error.message);
throw error; // rethrow: nothing can be fixed here
} finally {
console.log("Finished reading configuration");
}
}纯字符串构不成一套错误策略。扩展 Error 来创建携带结构化数据(HTTP 状态、无效字段)的类,这些数据可以用 instanceof 来区分。自 ES2022 起,cause 选项会把原始错误链接到高层错误上:你既能暴露一条清晰的业务消息,又不会丢失技术线索。
class ApiError extends Error {
constructor(message, status, options) {
super(message, options);
this.name = "ApiError";
this.status = status;
}
}
try {
const low = new Error("socket timeout");
throw new ApiError("Profile unavailable", 503,
{ cause: low });
} catch (error) {
if (error instanceof ApiError) {
console.error(error.status, error.cause.message);
}
}console 提供的远不止 log:console.table 会把对象集合排列成表格,group/groupEnd 会嵌套输出,time/timeEnd 会测量一段时长,console.assert 只在条件为假时才记录,而 console.trace 会打印当前的调用栈。这些工具组合起来,远胜于一场匿名 log 调用的倾盆大雨。
const users = [
{ name: "Ada", role: "admin" },
{ name: "Linus", role: "dev" },
];
console.table(users);
console.group("Checks");
console.assert(users.length > 0, "Empty list");
console.time("sort");
users.sort((a, b) => a.name.localeCompare(b.name));
console.timeEnd("sort");
console.groupEnd();finally 块在什么时候运行?cause 选项是用来做什么的?console.assert(condition, message) 的行为是什么?