常识来了
白蓝主题五 · 清爽阅读
首页  > 软件进阶

throw错误处理机制:让程序出错时不再“裸奔”

写代码就像做饭,再熟练的大厨也难免切到手或者炒糊菜。ref="/tag/46/" style="color:#C468A7;font-weight:bold;">程序运行时同样会遇到各种意外情况,比如读取一个不存在的文件、网络请求超时、用户输入了非法数据等。这时候,如果什么都不做,程序可能直接崩溃,用户一脸懵。于是,就有了 throw 错误处理机制——它是程序员手里的一把“报警器”,专门用来主动抛出问题,提醒系统“这里出事了”。

什么是 throw?

在 JavaScript、Java、C# 等语言中,throw 是一个关键字,用于手动抛出一个错误。它不解决错误,而是明确地“甩锅”——告诉程序:“别往下走了,现在就得处理这个事!”

举个例子:你开发一个转账功能,金额必须大于 0。如果用户填了个 -100,程序当然不能照单全收。这时候就可以用 throw 拦下来:

function transferMoney(amount) {
    if (amount <= 0) {
        throw new Error("转账金额必须大于 0");
    }
    // 正常执行转账逻辑
}

一旦执行到 throw,函数立刻停止,错误会被向上抛出,直到被某个 try...catch 捕获处理。

throw 能抛什么?

很多人以为 throw 只能抛错误对象,其实它可以抛任何东西——字符串、数字、对象都行。比如:

throw "用户名不能为空";
throw { code: 400, message: "请求参数错误" };
throw true;

但实际开发中,推荐还是抛出 Error 实例。因为它自带调用栈信息,方便排查问题。想象一下运维半夜被叫起来查 bug,看到的不是一句“出错了”,而是完整的错误类型、消息和堆栈路径,那体验差得可不是一点半点。

和 try...catch 配合使用

throw 负责制造问题,try...catch 负责收拾残局。它们经常成对出现:

try {
    transferMoney(-50);
} catch (error) {
    console.log("捕获到错误:", error.message);
    // 可以提示用户、上报日志或降级处理
}

如果没有 catch,错误就会一直往上冒泡,最终可能导致页面白屏或服务中断。这就像家里水管漏水,你不接盆也不修,最后淹了楼下邻居。

自定义错误类型

项目复杂了以后,光靠 Error 不够用。比如你要区分“网络错误”和“权限错误”,可以自己定义错误类:

class AuthError extends Error {
    constructor(message) {
        super(message);
        this.name = "AuthError";
    }
}

// 使用
throw new AuthError("用户未登录,无法访问该页面");

这样在 catch 里就能根据 error.name 做不同处理,比如跳转登录页或弹出提示框。

别滥用 throw

虽然 throw 很有用,但不能哪儿都扔。比如一个表单校验,连续抛出十几个错误,反而会让调用方难以处理。合理的做法是收集所有错误,一次性抛出一个结构化的错误对象。

另外,异步代码中使用 throw 要格外小心。在 Promise 中,直接 throw 会触发 reject;但在 setTimeout 里 throw,就可能没人接得住,变成全局未捕获异常。