知识篇 -- JS错误处理与健壮性

Ray Shine 2024/1/26 JavaScript进阶知识错误处理

在JavaScript编程中,错误是不可避免的。无论是语法错误、运行时错误还是逻辑错误,都可能导致程序中断或行为异常。有效的错误处理机制是构建健壮、可靠Web应用的关键。本文将深入探讨JavaScript中错误处理的各种方法,从基本的 try...catch 语句到自定义错误,以及异步操作中的错误处理。

# 一、try...catch 语句:捕获同步错误 同步

try...catch 是JavaScript中最基本的错误处理结构,用于捕获和处理同步代码中可能发生的错误。

  • try:包含可能抛出错误的代码。
  • catch:当 try 块中的代码抛出错误时,catch 块会被执行,并接收一个 Error 对象作为参数。
  • finally (可选):无论 try 块中的代码是否抛出错误,也无论 catch 块是否被执行,finally 块中的代码总会被执行。通常用于资源清理。

语法

try {
    // 可能会抛出错误的代码
} catch (error) {
    // 错误发生时执行的代码
    // error 参数包含了错误信息
} finally {
    // 无论是否发生错误,都会执行的代码
}

示例

function divide(a, b) {
    try {
        if (b === 0) {
            throw new Error("除数不能为0"); // 手动抛出错误
        }
        return a / b;
    } catch (error) {
        console.error("捕获到错误:", error.message); // 捕获并处理错误
        return NaN; // 返回一个特殊值表示失败
    } finally {
        console.log("除法操作尝试完成。");
    }
}

console.log(divide(10, 2)); // 输出:5, 除法操作尝试完成。
console.log(divide(10, 0)); // 输出:捕获到错误: 除数不能为0, 除法操作尝试完成。, NaN

# 二、Error 对象:错误的详细信息 错误类型

当JavaScript运行时发生错误时,会创建一个 Error 对象(或其子类的实例),其中包含了错误的详细信息。

  • Error 对象的属性

    • name:错误的类型(如 "ReferenceError", "TypeError", "RangeError")。
    • message:错误的详细描述信息。
    • stack:错误的堆栈跟踪信息,有助于定位错误发生的位置。
  • 常见的 Error 子类

    • ReferenceError:引用了未声明的变量。
    • TypeError:操作使用了错误的数据类型或值。
    • RangeError:数字超出有效范围。
    • SyntaxError:代码中存在语法错误(通常在解析阶段就会报错,无法被 try...catch 捕获)。
    • URIError:URI编码或解码函数使用不当。
    • EvalErroreval() 函数使用不当(ES6后已不常用)。

示例

try {
    const x = y + 1; // y未定义
} catch (error) {
    console.log("错误名称:", error.name);    // ReferenceError
    console.log("错误信息:", error.message); // y is not defined
    console.log("错误堆栈:", error.stack);   // 堆栈跟踪信息
}

# 三、自定义错误:创建更具语义的错误类型 扩展

在复杂的应用中,内置的 Error 类型可能不足以表达所有业务逻辑错误。我们可以通过继承 Error 类来创建自定义错误类型。

示例

class CustomValidationError extends Error {
    constructor(message, field) {
        super(message); // 调用父类Error的构造函数
        this.name = "CustomValidationError"; // 设置自定义错误名称
        this.field = field; // 添加自定义属性
    }
}

function validateInput(input) {
    if (!input || input.length < 5) {
        throw new CustomValidationError("输入长度不足", "username");
    }
    return true;
}

try {
    validateInput("abc");
} catch (error) {
    if (error instanceof CustomValidationError) {
        console.error(`自定义验证错误: ${error.message} (字段: ${error.field})`);
    } else {
        console.error("未知错误:", error);
    }
}

# 四、异步错误处理:Promise与Async/Await 异步

同步代码中的错误可以通过 try...catch 轻松捕获,但异步代码的错误处理则需要特殊考虑。

# 1. Promise中的错误处理 Promise

  • .catch() 方法:Promise链中的任何一个 reject 都会被最近的 .catch() 捕获。
  • Promise.prototype.finally() (ES2018新增):无论Promise成功或失败,都会执行的回调函数,常用于清理工作。

示例

function asyncOperation() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = Math.random() > 0.5;
            if (success) {
                resolve("异步操作成功!");
            } else {
                reject(new Error("异步操作失败!"));
            }
        }, 1000);
    });
}

asyncOperation()
    .then(result => console.log(result))
    .catch(error => console.error("Promise捕获到错误:", error.message))
    .finally(() => console.log("异步操作完成。"));

注意:如果没有 .catch() 捕获 rejected 的Promise,错误会冒泡到全局,导致未捕获的Promise拒绝错误。

# 2. Async/Await中的错误处理 Async/Await

async/await 使得异步错误处理变得和同步错误处理一样简单,可以直接使用 try...catch

示例

async function performAsyncTasks() {
    try {
        console.log("开始执行异步任务...");
        const result = await asyncOperation(); // await会等待Promise解决或拒绝
        console.log(result);
    } catch (error) {
        console.error("Async/Await捕获到错误:", error.message);
    } finally {
        console.log("异步任务执行完毕。");
    }
}

performAsyncTasks();

# 五、全局错误处理 全局

  • window.onerror:用于捕获未被 try...catch 捕获的全局运行时错误。
    window.onerror = function(message, source, lineno, colno, error) {
        console.error("全局错误:", message, source, lineno, colno, error);
        // 返回 true 可以阻止浏览器默认的错误处理(例如在控制台打印错误)
        return true;
    };
    // 故意制造一个错误
    // nonExistentFunction();
    
  • window.addEventListener('unhandledrejection', ...):用于捕获未被处理的Promise拒绝错误。
    window.addEventListener('unhandledrejection', function(event) {
        console.error("未处理的Promise拒绝:", event.promise, event.reason);
        // 阻止默认行为(例如在控制台打印警告)
        event.preventDefault();
    });
    // 故意制造一个未捕获的Promise拒绝
    // Promise.reject("Something went wrong!");
    

有效的错误处理是构建高质量JavaScript应用不可或缺的一部分。通过合理运用 try...catch、Promise链、Async/Await以及全局错误监听,可以确保程序在面对异常情况时依然能够优雅地运行,并提供有用的反馈。

最后更新时间: 2025/11/20 22:59:30
ON THIS PAGE