JavaScript的秘密生活:拒绝

发布: (2026年2月20日 GMT+8 16:42)
3 分钟阅读
原文: Dev.to

Source: Dev.to

为什么 async 错误会绕过 try/catch

Timothy 在应用程序的最顶部放置了一个 try/catch 块,确信任何错误都会被捕获:

function loadDashboard() {
    try {
        // Initiating a background network request
        fetch('/api/corrupted-data');
        console.log("Dashboard loading...");
    } catch (error) {
        console.error("Safe Landing:", error.message);
    }
}

loadDashboard();

控制台打印了 Dashboard loading…。两秒后进程崩溃,出现:

UnhandledPromiseRejection: Failed to fetch

发生了什么?

  1. fetch() 会立即返回一个 pending Promise;它 不会 等待网络请求完成。
  2. try 块成功结束,调用栈被弹出,catch 块随之被丢弃。
  3. 当 Promise 稍后被拒绝时,已经没有原始 try/catch 所在的栈帧来处理错误。此时的拒绝会成为 未处理的 Promise 拒绝,现代浏览器和 Node.js 会将其视为致命错误。

将错误处理器附加到 Promise 上

解决办法是 直接在 Promise 上 附加处理器:

function loadDashboard() {
    fetch('/api/corrupted-data')
        .then(data => console.log("Data loaded!"))
        .catch(error => console.error("Safe Landing:", error.message));

    console.log("Dashboard loading...");
}
  • catch 方法在 Promise 本身上创建了一个错误边界,当网络请求失败时,拒绝会被路由到该处理器,而不是漂浮到外部。

使用 async/await 配合 try/catch

如果你更喜欢 try/catch 语法,await 会暂停函数执行并保留错误边界:

async function loadDashboard() {
    try {
        console.log("Dashboard loading..."); // moved before the await

        // Execution is suspended here; the try/catch stays in memory.
        await fetch('/api/corrupted-data');

        console.log("Data loaded successfully!");
    } catch (error) {
        console.error("Safe Landing:", error.message);
    }
}
  • await 遇到被拒绝的 Promise 时,引擎会 恢复 函数执行,恢复 try/catch 上下文,并抛出错误,随后被外层的 catch 捕获。

高级技巧:回调和事件监听器

回调(例如 setTimeout、DOM 事件监听器)会在全新的调用栈中运行。把注册代码包在 try/catch并不能 保护回调体。

// ❌ WRONG: The try/catch runs during setup, not when the event fires.
try {
    button.addEventListener('click', () => {
        throw new Error("Click failed!"); // crashes the app
    });
} catch (e) {
    // This block is long gone by the time the click occurs.
}
// ✅ RIGHT: Place the try/catch **inside** the callback.
button.addEventListener('click', () => {
    try {
        throw new Error("Click failed!"); // caught safely
    } catch (e) {
        console.error("Safe Landing:", e.message);
    }
});
0 浏览
Back to Blog

相关文章

阅读更多 »