⚠️ 第十二章:错误处理与资源管理

掌握优雅的错误处理和资源管理技巧

12.1 try...catch...finally 最佳实践

// 基本用法
try {
    // 可能抛出错误的代码
    const result = 10 / 0;
} catch (error) {
    // 处理错误
    console.error(error);
} finally {
    // 无论是否出错都会执行的代码
    console.log('操作完成');
}

// 异步错误处理
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('Fetch error:', error);
        throw error;
    }
}

12.2 自定义错误类

// 自定义错误类
class AppError extends Error {
    constructor(message, statusCode) {
        super(message);
        this.name = 'AppError';
        this.statusCode = statusCode;
        this.status = statusCode >= 400 && statusCode < 500 ? 'fail' : 'error';
        
        Error.captureStackTrace(this, this.constructor);
    }
}

// 使用自定义错误
function divide(a, b) {
    if (b === 0) {
        throw new AppError('除数不能为零', 400);
    }
    return a / b;
}

try {
    divide(10, 0);
} catch (error) {
    if (error instanceof AppError) {
        console.error(error.statusCode, error.message);
    } else {
        console.error(error);
    }
}

12.3 ES2026 新特性:可靠错误与错误原因链

// 错误原因链
try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) {
        throw new Error('Network response was not ok', {
            cause: { status: response.status, statusText: response.statusText }
        });
    }
} catch (error) {
    console.error(error.message);
    console.error(error.cause);
}

// 嵌套错误
try {
    try {
        throw new Error('Inner error');
    } catch (innerError) {
        throw new Error('Outer error', { cause: innerError });
    }
} catch (outerError) {
    console.error(outerError.message); // Outer error
    console.error(outerError.cause.message); // Inner error
}

12.4 ES2026 新特性:资源管理

using 关键字用于自动管理资源,确保资源在使用后被正确释放。
// 实现 Disposable 接口
class FileHandle {
    constructor(filename) {
        this.filename = filename;
        this.handle = null;
    }
    
    async open() {
        // 模拟打开文件
        this.handle = 'file handle';
        console.log(`Opening file ${this.filename}`);
        return this;
    }
    
    close() {
        if (this.handle) {
            console.log(`Closing file ${this.filename}`);
            this.handle = null;
        }
    }
    
    [Symbol.dispose]() {
        this.close();
    }
}

// 使用 using 关键字
async function processFile() {
    using fileHandle = await new FileHandle('data.txt').open();
    
    // 使用 fileHandle
    console.log('Processing file...');
    
    // 函数结束时,fileHandle 会自动关闭
}

processFile();

动手练习

练习 1:try...catch...finally

  1. 使用 try...catch 处理错误
  2. 添加 finally 块清理资源
  3. 测试不同类型的错误

练习 2:自定义错误类

  1. 创建一个自定义错误类
  2. 添加自定义属性和方法
  3. 测试自定义错误

练习 3:错误原因链

  1. 创建带有 cause 的错误
  2. 测试嵌套错误
  3. 分析错误原因链

练习 4:资源管理

  1. 实现一个 Disposable 类
  2. 使用 using 关键字管理资源
  3. 测试资源自动释放