Skip to content

Web 错误处理

错误处理基础

1. 使用 try-catch

所有异步操作都应该使用 try-catch 进行错误处理:

javascript
try {
    const config = new EngineConfig({
        appId: 'your-app-id',
        appKey: 'your-app-key'
    });
    
    const engine = new BeautyEffectEngine(config);
    await engine.init();
    
    console.log('引擎初始化成功');
} catch (error) {
    if (error instanceof FacebetterError) {
        console.error('Facebetter 错误:', error.message);
        console.error('错误代码:', error.code);
    } else {
        console.error('未知错误:', error);
    }
}

2. 检查引擎初始化

javascript
let engine = null;

try {
    const config = new EngineConfig({
        appId: 'your-app-id',
        appKey: 'your-app-key'
    });
    
    engine = new BeautyEffectEngine(config);
    await engine.init();
    
    if (!engine || !engine.initialized) {
        throw new Error('引擎初始化失败');
    }
} catch (error) {
    console.error('引擎初始化失败:', error);
    // 处理错误,如显示用户提示
    showErrorToUser('美颜引擎初始化失败,请刷新页面重试');
}

3. 检查 API 调用结果

javascript
try {
    engine.setBeautyTypeEnabled(BeautyType.Basic, true);
    console.log('成功启用基础美颜');
} catch (error) {
    console.error('启用基础美颜失败:', error);
    // 处理错误
}

try {
    engine.setBasicParam(BasicParam.Whitening, 0.5);
} catch (error) {
    console.error('设置参数失败:', error);
}

常见错误码

FacebetterError 错误码

FacebetterError 的错误码可以是数字或字符串:

数字错误码(来自 WASM 层):

  • 0: 成功
  • -1: 通用错误(引擎未初始化、参数无效等)
  • 其他负数: 根据具体操作返回的错误码

字符串错误码(来自 JS 层):

  • 'TIMEOUT': 操作超时(WASM 加载超时、认证超时等)
  • 'NETWORK_ERROR': 网络错误(在线认证失败等)
  • 'WASM_LOAD_ERROR': WASM 模块加载失败
  • 'LICENSE_ERROR': 许可证验证失败
  • 'AUTH_TIMEOUT': 在线认证超时
  • 'AUTH_EMPTY_RESPONSE': 在线认证返回空响应
  • 'ENGINE_CREATE_FAILED': 引擎创建失败(可能是许可证或资源路径问题)
  • 'UNKNOWN_ERROR': 未知错误
javascript
try {
    await engine.init();
} catch (error) {
    if (error instanceof FacebetterError) {
        if (typeof error.code === 'string') {
            // 字符串错误码
            switch (error.code) {
                case 'TIMEOUT':
                    console.error('操作超时:', error.message);
                    break;
                case 'NETWORK_ERROR':
                    console.error('网络错误:', error.message);
                    break;
                case 'WASM_LOAD_ERROR':
                    console.error('WASM 加载失败:', error.message);
                    break;
                case 'LICENSE_ERROR':
                case 'ENGINE_CREATE_FAILED':
                    console.error('许可证错误:', error.message);
                    break;
                default:
                    console.error('错误:', error.code, error.message);
            }
        } else {
            // 数字错误码
            switch (error.code) {
                case -1:
                    console.error('通用错误:', error.message);
                    break;
                default:
                    console.error('错误码:', error.code, error.message);
            }
        }
    }
}

处理图像数据错误

1. 输入图像验证

javascript
function validateImageData(imageData) {
    if (!imageData) {
        throw new Error('图像数据不能为空');
    }
    
    if (!(imageData instanceof ImageData)) {
        throw new Error('图像数据必须是 ImageData 类型');
    }
    
    if (imageData.width <= 0 || imageData.height <= 0) {
        throw new Error('图像尺寸无效');
    }
    
    if (!imageData.data || imageData.data.length === 0) {
        throw new Error('图像数据为空');
    }
    
    return true;
}

function processImageSafe(imageData, engine) {
    try {
        // 验证输入
        validateImageData(imageData);
        
        // 处理图像(同步方法)
        const result = engine.processImage(
            imageData, 
            imageData.width, 
            imageData.height, 
            ProcessMode.Video
        );
        
        return result;
    } catch (error) {
        console.error('图像处理失败:', error);
        throw error;
    }
}

2. Canvas 错误处理

javascript
function getImageDataFromCanvas(canvas) {
    try {
        if (!canvas) {
            throw new Error('Canvas 元素不存在');
        }
        
        const ctx = canvas.getContext('2d');
        if (!ctx) {
            throw new Error('无法获取 Canvas 上下文');
        }
        
        if (canvas.width === 0 || canvas.height === 0) {
            throw new Error('Canvas 尺寸无效');
        }
        
        return ctx.getImageData(0, 0, canvas.width, canvas.height);
    } catch (error) {
        console.error('获取 Canvas 图像数据失败:', error);
        throw error;
    }
}

网络错误处理

1. 在线验证错误

javascript
async function initEngineWithRetry(config, maxRetries = 3) {
    for (let i = 0; i < maxRetries; i++) {
        try {
            const engine = new BeautyEffectEngine(config);
            await engine.init();
            return engine;
        } catch (error) {
            if (error.message.includes('network') || error.message.includes('fetch')) {
                console.warn(`初始化失败(尝试 ${i + 1}/${maxRetries}):`, error.message);
                
                if (i < maxRetries - 1) {
                    // 等待后重试
                    await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
                    continue;
                }
            }
            
            throw error;
        }
    }
}

// 使用
try {
    const engine = await initEngineWithRetry(config);
} catch (error) {
    console.error('初始化失败,已重试多次:', error);
}

2. WASM 加载错误

javascript
async function loadEngineWithFallback() {
    try {
        const engine = new BeautyEffectEngine(config);
        await engine.init();
        return engine;
    } catch (error) {
        if (error.message.includes('WASM') || error.message.includes('wasm')) {
            console.error('WASM 加载失败:', error);
            // 可以尝试重新加载或使用备用方案
            showErrorToUser('美颜功能暂时不可用,请刷新页面重试');
        }
        throw error;
    }
}

错误处理最佳实践

1. 统一错误处理函数

javascript
class ErrorHandler {
    static handle(error, context = '') {
        console.error(`[${context}] 错误:`, error);
        
        if (error instanceof FacebetterError) {
            // Facebetter 特定错误
            this.handleFacebetterError(error, context);
        } else if (error instanceof Error) {
            // 通用错误
            this.handleGenericError(error, context);
        } else {
            // 未知错误
            console.error('未知错误类型:', error);
        }
    }
    
    static handleFacebetterError(error, context) {
        switch (error.code) {
            case -1:
                console.error('Facebetter 通用错误:', error.message);
                break;
            default:
                console.error('Facebetter 错误:', error.code, error.message);
        }
    }
    
    static handleGenericError(error, context) {
        if (error.message.includes('network')) {
            console.error('网络错误:', error.message);
        } else if (error.message.includes('WASM')) {
            console.error('WASM 错误:', error.message);
        } else {
            console.error('通用错误:', error.message);
        }
    }
}

// 使用
try {
    await engine.init();
} catch (error) {
    ErrorHandler.handle(error, '引擎初始化');
}

2. 用户友好的错误提示

javascript
function showErrorToUser(message) {
    // 显示用户友好的错误提示
    const errorDiv = document.createElement('div');
    errorDiv.className = 'error-message';
    errorDiv.textContent = message;
    document.body.appendChild(errorDiv);
    
    // 3秒后自动隐藏
    setTimeout(() => {
        errorDiv.remove();
    }, 3000);
}

try {
    await engine.init();
} catch (error) {
    let userMessage = '美颜功能初始化失败';
    
    if (error.message.includes('network')) {
        userMessage = '网络连接失败,请检查网络后重试';
    } else if (error.message.includes('WASM')) {
        userMessage = '浏览器不支持或加载失败,请刷新页面重试';
    } else if (error.message.includes('appId') || error.message.includes('appKey')) {
        userMessage = '配置错误,请联系技术支持';
    }
    
    showErrorToUser(userMessage);
    console.error('详细错误:', error);
}

3. 错误日志记录

javascript
class ErrorLogger {
    static log(error, context = '', userInfo = {}) {
        const errorLog = {
            timestamp: new Date().toISOString(),
            context: context,
            error: {
                message: error.message,
                code: error.code || 'N/A',
                stack: error.stack
            },
            userInfo: userInfo,
            userAgent: navigator.userAgent,
            url: window.location.href
        };
        
        // 发送到服务器(可选)
        if (window.fetch) {
            fetch('/api/errors', {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(errorLog)
            }).catch(err => console.error('发送错误日志失败:', err));
        }
        
        // 控制台输出
        console.error('错误日志:', errorLog);
    }
}

// 使用
try {
    await engine.init();
} catch (error) {
    ErrorLogger.log(error, '引擎初始化', {
        appId: config.appId ? 'provided' : 'missing'
    });
}

预防性错误处理

1. 参数验证

javascript
function validateBeautyParam(value) {
    if (typeof value !== 'number') {
        throw new TypeError('参数值必须是数字');
    }
    
    if (value < 0 || value > 1) {
        throw new RangeError('参数值必须在 0.0-1.0 之间');
    }
    
    return true;
}

function setBasicParamSafe(engine, param, value) {
    try {
        validateBeautyParam(value);
        engine.setBasicParam(param, value);
    } catch (error) {
        console.error('设置参数失败:', error);
        throw error;
    }
}

2. 状态检查

javascript
function processImageWithValidation(engine, imageData) {
    if (!engine) {
        throw new Error('引擎未创建');
    }
    
    if (!engine.initialized) {
        throw new Error('引擎未初始化');
    }
    
    if (!imageData) {
        throw new Error('图像数据不能为空');
    }
    
    // 处理图像(同步方法)
    return engine.processImage(
        imageData, 
        imageData.width, 
        imageData.height, 
        ProcessMode.Video
    );
}

相关文档