错误类型和异常处理
JavaScript中的错误类型
// JavaScript中的内置错误类型
// 1. Error - 通用错误类型
try {
throw new Error('这是一个通用错误');
} catch (error) {
console.log('错误类型:', error.constructor.name); // "Error"
console.log('错误消息:', error.message);
console.log('错误堆栈:', error.stack);
}
// 2. SyntaxError - 语法错误
try {
eval('var a = ;'); // 语法错误
} catch (error) {
console.log('语法错误:', error.message);
}
// 3. ReferenceError - 引用错误
try {
console.log(undefinedVariable); // 引用未定义的变量
} catch (error) {
console.log('引用错误:', error.message);
}
// 4. TypeError - 类型错误
try {
null.someMethod(); // 在null上调用方法
} catch (error) {
console.log('类型错误:', error.message);
}
// 5. RangeError - 范围错误
try {
const arr = new Array(-1); // 负数长度
} catch (error) {
console.log('范围错误:', error.message);
}
// 6. URIError - URI错误
try {
decodeURIComponent('%'); // 无效的URI组件
} catch (error) {
console.log('URI错误:', error.message);
}
// 7. EvalError - eval错误(很少使用)
// 现代JavaScript中很少遇到
// 错误对象的属性
function demonstrateErrorProperties() {
try {
throw new Error('演示错误属性');
} catch (error) {
console.log('错误属性演示:');
console.log('name:', error.name); // 错误名称
console.log('message:', error.message); // 错误消息
console.log('stack:', error.stack); // 堆栈跟踪
console.log('fileName:', error.fileName); // 文件名(某些浏览器)
console.log('lineNumber:', error.lineNumber); // 行号(某些浏览器)
console.log('columnNumber:', error.columnNumber); // 列号(某些浏览器)
}
}
demonstrateErrorProperties();
// 检查错误类型
function handleDifferentErrors() {
const errors = [
new Error('通用错误'),
new TypeError('类型错误'),
new ReferenceError('引用错误'),
new RangeError('范围错误')
];
errors.forEach(error => {
try {
throw error;
} catch (e) {
if (e instanceof TypeError) {
console.log('处理类型错误:', e.message);
} else if (e instanceof ReferenceError) {
console.log('处理引用错误:', e.message);
} else if (e instanceof RangeError) {
console.log('处理范围错误:', e.message);
} else {
console.log('处理通用错误:', e.message);
}
}
});
}
handleDifferentErrors();
// 自定义错误类型
class CustomError extends Error {
constructor(message, code, details) {
super(message);
this.name = 'CustomError';
this.code = code;
this.details = details;
this.timestamp = new Date().toISOString();
// 确保堆栈跟踪正确
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomError);
}
}
toJSON() {
return {
name: this.name,
message: this.message,
code: this.code,
details: this.details,
timestamp: this.timestamp,
stack: this.stack
};
}
}
// 特定的自定义错误类型
class ValidationError extends CustomError {
constructor(field, value, rule) {
super(`验证失败: ${field}`, 'VALIDATION_ERROR', {
field,
value,
rule
});
this.name = 'ValidationError';
}
}
class NetworkError extends CustomError {
constructor(url, status, statusText) {
super(`网络请求失败: ${status} ${statusText}`, 'NETWORK_ERROR', {
url,
status,
statusText
});
this.name = 'NetworkError';
}
}
class BusinessLogicError extends CustomError {
constructor(operation, reason) {
super(`业务逻辑错误: ${operation}`, 'BUSINESS_ERROR', {
operation,
reason
});
this.name = 'BusinessLogicError';
}
}
// 使用自定义错误
function validateUser(user) {
if (!user.name) {
throw new ValidationError('name', user.name, 'required');
}
if (user.age < 0 || user.age > 150) {
throw new ValidationError('age', user.age, 'range:0-150');
}
if (!user.email || !user.email.includes('@')) {
throw new ValidationError('email', user.email, 'format:email');
}
}
function processUser(user) {
try {
validateUser(user);
console.log('用户验证通过:', user.name);
} catch (error) {
if (error instanceof ValidationError) {
console.error('验证错误:', {
field: error.details.field,
value: error.details.value,
rule: error.details.rule,
timestamp: error.timestamp
});
} else {
console.error('未知错误:', error.message);
}
}
}
// 测试自定义错误
processUser({ name: '', age: 25, email: 'test@example.com' });
processUser({ name: '张三', age: -5, email: 'test@example.com' });
processUser({ name: '李四', age: 30, email: 'invalid-email' });
processUser({ name: '王五', age: 25, email: 'test@example.com' });
try-catch-finally语句
// 基本的try-catch-finally结构
function demonstrateTryCatchFinally() {
console.log('=== try-catch-finally演示 ===');
try {
console.log('1. 执行try块');
// 模拟可能出错的操作
const randomError = Math.random() > 0.5;
if (randomError) {
throw new Error('随机错误发生了');
}
console.log('2. try块执行成功');
return 'success';
} catch (error) {
console.log('3. 捕获到错误:', error.message);
return 'error';
} finally {
console.log('4. finally块总是执行');
// 注意:finally块中的return会覆盖try/catch中的return
}
}
// 多次调用查看不同结果
for (let i = 0; i < 3; i++) {
console.log('结果:', demonstrateTryCatchFinally());
console.log('---');
}
// 嵌套的try-catch
function nestedTryCatch() {
try {
console.log('外层try开始');
try {
console.log('内层try开始');
throw new Error('内层错误');
} catch (innerError) {
console.log('内层catch:', innerError.message);
throw new Error('重新抛出的错误');
} finally {
console.log('内层finally');
}
} catch (outerError) {
console.log('外层catch:', outerError.message);
} finally {
console.log('外层finally');
}
}
nestedTryCatch();
// 资源管理模式
class Resource {
constructor(name) {
this.name = name;
this.isOpen = false;
console.log(`资源 ${this.name} 创建`);
}
open() {
if (this.isOpen) {
throw new Error(`资源 ${this.name} 已经打开`);
}
this.isOpen = true;
console.log(`资源 ${this.name} 打开`);
}
use() {
if (!this.isOpen) {
throw new Error(`资源 ${this.name} 未打开`);
}
console.log(`使用资源 ${this.name}`);
// 模拟使用过程中可能出错
if (Math.random() > 0.7) {
throw new Error(`使用资源 ${this.name} 时发生错误`);
}
}
close() {
if (this.isOpen) {
this.isOpen = false;
console.log(`资源 ${this.name} 关闭`);
}
}
}
function useResource(resourceName) {
const resource = new Resource(resourceName);
try {
resource.open();
resource.use();
console.log(`资源 ${resourceName} 使用成功`);
} catch (error) {
console.error(`资源 ${resourceName} 使用失败:`, error.message);
} finally {
// 确保资源总是被正确关闭
resource.close();
}
}
// 测试资源管理
useResource('数据库连接');
useResource('文件句柄');
useResource('网络连接');
// 使用with语句模拟的资源管理器
class ResourceManager {
constructor(resource) {
this.resource = resource;
}
async use(callback) {
try {
this.resource.open();
return await callback(this.resource);
} catch (error) {
console.error('资源使用错误:', error.message);
throw error;
} finally {
this.resource.close();
}
}
}
// 使用资源管理器
async function demonstrateResourceManager() {
const resource = new Resource('托管资源');
const manager = new ResourceManager(resource);
try {
await manager.use(async (res) => {
res.use();
// 模拟异步操作
await new Promise(resolve => setTimeout(resolve, 100));
console.log('异步操作完成');
});
} catch (error) {
console.error('托管资源使用失败:', error.message);
}
}
demonstrateResourceManager();
// 错误边界模式(类似React的错误边界)
class ErrorBoundary {
constructor(fallback) {
this.fallback = fallback;
this.hasError = false;
this.error = null;
}
wrap(fn) {
return (...args) => {
try {
this.hasError = false;
this.error = null;
return fn(...args);
} catch (error) {
this.hasError = true;
this.error = error;
console.error('ErrorBoundary捕获错误:', error.message);
return this.fallback(error);
}
};
}
getErrorInfo() {
return {
hasError: this.hasError,
error: this.error
};
}
reset() {
this.hasError = false;
this.error = null;
}
}
// 使用错误边界
const errorBoundary = new ErrorBoundary((error) => {
return `发生错误,显示备用内容: ${error.message}`;
});
const riskyFunction = errorBoundary.wrap((x) => {
if (x < 0) {
throw new Error('输入不能为负数');
}
return x * 2;
});
console.log(riskyFunction(5)); // 正常执行
console.log(riskyFunction(-3)); // 触发错误边界
console.log('错误信息:', errorBoundary.getErrorInfo());
异步错误处理
Promise错误处理
// Promise中的错误处理
// 1. 使用.catch()方法
function promiseErrorHandling() {
console.log('=== Promise错误处理 ===');
// 创建一个可能失败的Promise
function createPromise(shouldFail = false) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject(new Error('Promise执行失败'));
} else {
resolve('Promise执行成功');
}
}, 100);
});
}
// 成功的情况
createPromise(false)
.then(result => {
console.log('成功:', result);
})
.catch(error => {
console.error('错误:', error.message);
});
// 失败的情况
createPromise(true)
.then(result => {
console.log('成功:', result);
})
.catch(error => {
console.error('错误:', error.message);
});
}
promiseErrorHandling();
// 2. Promise链中的错误传播
function promiseChainErrorHandling() {
console.log('=== Promise链错误处理 ===');
Promise.resolve(10)
.then(value => {
console.log('步骤1:', value);
return value * 2;
})
.then(value => {
console.log('步骤2:', value);
if (value > 15) {
throw new Error('值太大了');
}
return value + 5;
})
.then(value => {
console.log('步骤3:', value); // 这一步不会执行
return value;
})
.catch(error => {
console.error('链中捕获错误:', error.message);
return 0; // 返回默认值
})
.then(value => {
console.log('最终结果:', value); // 会执行,值为0
});
}
promiseChainErrorHandling();
// 3. 多个Promise的错误处理
function multiplePromiseErrorHandling() {
console.log('=== 多个Promise错误处理 ===');
const promises = [
Promise.resolve('成功1'),
Promise.reject(new Error('失败2')),
Promise.resolve('成功3'),
Promise.reject(new Error('失败4'))
];
// Promise.all - 任何一个失败就失败
Promise.all(promises)
.then(results => {
console.log('所有成功:', results);
})
.catch(error => {
console.error('Promise.all失败:', error.message);
});
// Promise.allSettled - 等待所有完成
Promise.allSettled(promises)
.then(results => {
console.log('Promise.allSettled结果:');
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(` ${index}: 成功 -`, result.value);
} else {
console.log(` ${index}: 失败 -`, result.reason.message);
}
});
});
// 手动处理每个Promise的错误
const safePromises = promises.map(promise =>
promise.catch(error => ({ error: error.message }))
);
Promise.all(safePromises)
.then(results => {
console.log('安全处理结果:');
results.forEach((result, index) => {
if (result.error) {
console.log(` ${index}: 错误 -`, result.error);
} else {
console.log(` ${index}: 成功 -`, result);
}
});
});
}
multiplePromiseErrorHandling();
// 4. 重试机制
class RetryablePromise {
static async retry(fn, maxAttempts = 3, delay = 1000) {
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
console.log(`尝试第 ${attempt} 次`);
const result = await fn();
console.log(`第 ${attempt} 次尝试成功`);
return result;
} catch (error) {
lastError = error;
console.log(`第 ${attempt} 次尝试失败:`, error.message);
if (attempt < maxAttempts) {
console.log(`等待 ${delay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // 指数退避
}
}
}
throw new Error(`重试 ${maxAttempts} 次后仍然失败: ${lastError.message}`);
}
static async retryWithCondition(fn, shouldRetry, maxAttempts = 3, delay = 1000) {
let lastError;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
const result = await fn();
return result;
} catch (error) {
lastError = error;
console.log(`第 ${attempt} 次尝试失败:`, error.message);
if (attempt < maxAttempts && shouldRetry(error)) {
console.log(`错误可重试,等待 ${delay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2;
} else {
break;
}
}
}
throw lastError;
}
}
// 使用重试机制
async function demonstrateRetry() {
console.log('=== 重试机制演示 ===');
// 模拟不稳定的网络请求
let attemptCount = 0;
const unstableRequest = () => {
attemptCount++;
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.7) {
resolve(`请求成功,尝试了 ${attemptCount} 次`);
} else {
reject(new Error(`网络错误 (尝试 ${attemptCount})`);
}
}, 100);
});
};
try {
const result = await RetryablePromise.retry(unstableRequest, 5, 200);
console.log('最终结果:', result);
} catch (error) {
console.error('重试失败:', error.message);
}
// 条件重试示例
const conditionalRequest = () => {
const errorTypes = ['NETWORK_ERROR', 'TIMEOUT', 'AUTH_ERROR', 'SERVER_ERROR'];
const randomError = errorTypes[Math.floor(Math.random() * errorTypes.length)];
return Promise.reject(new NetworkError('https://api.example.com', 500, randomError));
};
try {
await RetryablePromise.retryWithCondition(
conditionalRequest,
(error) => {
// 只重试网络错误和超时错误
return error.details.statusText === 'NETWORK_ERROR' ||
error.details.statusText === 'TIMEOUT';
},
3,
500
);
} catch (error) {
console.error('条件重试失败:', error.message);
}
}
demonstrateRetry();
async/await错误处理
// async/await中的错误处理
// 1. 基本的async/await错误处理
async function basicAsyncErrorHandling() {
console.log('=== async/await基本错误处理 ===');
async function riskyAsyncFunction(shouldFail = false) {
await new Promise(resolve => setTimeout(resolve, 100));
if (shouldFail) {
throw new Error('异步函数执行失败');
}
return '异步函数执行成功';
}
// 成功的情况
try {
const result = await riskyAsyncFunction(false);
console.log('成功:', result);
} catch (error) {
console.error('错误:', error.message);
}
// 失败的情况
try {
const result = await riskyAsyncFunction(true);
console.log('成功:', result);
} catch (error) {
console.error('错误:', error.message);
}
}
basicAsyncErrorHandling();
// 2. 多个异步操作的错误处理
async function multipleAsyncErrorHandling() {
console.log('=== 多个异步操作错误处理 ===');
async function fetchData(id, shouldFail = false) {
await new Promise(resolve => setTimeout(resolve, Math.random() * 200));
if (shouldFail) {
throw new Error(`获取数据 ${id} 失败`);
}
return `数据 ${id}`;
}
// 顺序执行,遇到错误就停止
try {
const data1 = await fetchData(1, false);
console.log('获取到:', data1);
const data2 = await fetchData(2, true); // 这里会失败
console.log('获取到:', data2);
const data3 = await fetchData(3, false); // 不会执行
console.log('获取到:', data3);
} catch (error) {
console.error('顺序执行失败:', error.message);
}
// 并行执行,处理部分失败
const results = await Promise.allSettled([
fetchData(4, false),
fetchData(5, true),
fetchData(6, false)
]);
console.log('并行执行结果:');
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(` 数据 ${index + 4}: 成功 -`, result.value);
} else {
console.log(` 数据 ${index + 4}: 失败 -`, result.reason.message);
}
});
}
multipleAsyncErrorHandling();
// 3. 异步错误处理工具类
class AsyncErrorHandler {
// 安全执行异步函数
static async safe(asyncFn, defaultValue = null) {
try {
return await asyncFn();
} catch (error) {
console.error('AsyncErrorHandler.safe捕获错误:', error.message);
return defaultValue;
}
}
// 带超时的异步执行
static async withTimeout(asyncFn, timeoutMs = 5000) {
const timeoutPromise = new Promise((_, reject) => {
setTimeout(() => {
reject(new Error(`操作超时 (${timeoutMs}ms)`));
}, timeoutMs);
});
return Promise.race([asyncFn(), timeoutPromise]);
}
// 批量执行异步操作,收集所有结果
static async batch(asyncFunctions, concurrency = 3) {
const results = [];
const errors = [];
// 分批执行
for (let i = 0; i < asyncFunctions.length; i += concurrency) {
const batch = asyncFunctions.slice(i, i + concurrency);
const batchResults = await Promise.allSettled(
batch.map(fn => fn())
);
batchResults.forEach((result, index) => {
const globalIndex = i + index;
if (result.status === 'fulfilled') {
results[globalIndex] = result.value;
} else {
errors[globalIndex] = result.reason;
}
});
}
return { results, errors };
}
// 带重试的异步执行
static async withRetry(asyncFn, options = {}) {
const {
maxAttempts = 3,
delay = 1000,
backoff = 2,
shouldRetry = () => true
} = options;
let lastError;
let currentDelay = delay;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await asyncFn();
} catch (error) {
lastError = error;
if (attempt < maxAttempts && shouldRetry(error)) {
console.log(`重试第 ${attempt} 次失败,${currentDelay}ms后重试`);
await new Promise(resolve => setTimeout(resolve, currentDelay));
currentDelay *= backoff;
} else {
break;
}
}
}
throw lastError;
}
}
// 使用异步错误处理工具
async function demonstrateAsyncErrorHandler() {
console.log('=== 异步错误处理工具演示 ===');
// 安全执行
const safeResult = await AsyncErrorHandler.safe(
async () => {
throw new Error('这会失败');
},
'默认值'
);
console.log('安全执行结果:', safeResult);
// 超时控制
try {
await AsyncErrorHandler.withTimeout(
async () => {
await new Promise(resolve => setTimeout(resolve, 3000));
return '慢操作完成';
},
1000
);
} catch (error) {
console.error('超时错误:', error.message);
}
// 批量执行
const asyncTasks = [
async () => { await new Promise(r => setTimeout(r, 100)); return '任务1'; },
async () => { throw new Error('任务2失败'); },
async () => { await new Promise(r => setTimeout(r, 200)); return '任务3'; },
async () => { await new Promise(r => setTimeout(r, 150)); return '任务4'; }
];
const { results, errors } = await AsyncErrorHandler.batch(asyncTasks, 2);
console.log('批量执行结果:', results);
console.log('批量执行错误:', errors);
// 带重试的执行
let retryCount = 0;
try {
const retryResult = await AsyncErrorHandler.withRetry(
async () => {
retryCount++;
if (retryCount < 3) {
throw new Error(`第${retryCount}次尝试失败`);
}
return '重试成功';
},
{
maxAttempts: 5,
delay: 100,
backoff: 1.5
}
);
console.log('重试结果:', retryResult);
} catch (error) {
console.error('重试最终失败:', error.message);
}
}
demonstrateAsyncErrorHandler();
调试技巧和工具
浏览器调试工具
// 浏览器调试技巧
// 1. console对象的高级用法
function advancedConsoleUsage() {
console.log('=== 高级Console用法 ===');
// 基本日志级别
console.log('普通日志');
console.info('信息日志');
console.warn('警告日志');
console.error('错误日志');
// 分组日志
console.group('用户操作');
console.log('用户登录');
console.log('用户浏览商品');
console.groupCollapsed('购买流程'); // 默认折叠
console.log('添加到购物车');
console.log('结算');
console.log('支付');
console.groupEnd();
console.groupEnd();
// 表格显示
const users = [
{ id: 1, name: '张三', age: 25, city: '北京' },
{ id: 2, name: '李四', age: 30, city: '上海' },
{ id: 3, name: '王五', age: 28, city: '广州' }
];
console.table(users);
// 计时
console.time('数组排序');
const largeArray = Array.from({ length: 100000 }, () => Math.random());
largeArray.sort();
console.timeEnd('数组排序');
// 计数
for (let i = 0; i < 5; i++) {
console.count('循环计数');
}
console.countReset('循环计数');
// 断言
console.assert(2 + 2 === 4, '数学没问题');
console.assert(2 + 2 === 5, '数学有问题', { expected: 5, actual: 4 });
// 堆栈跟踪
function level1() {
function level2() {
function level3() {
console.trace('堆栈跟踪');
}
level3();
}
level2();
}
level1();
// 样式化输出
console.log('%c这是红色文字', 'color: red; font-size: 16px; font-weight: bold;');
console.log('%c这是蓝色背景', 'background: blue; color: white; padding: 5px;');
// 目录显示
const complexObject = {
user: {
profile: {
personal: { name: '张三', age: 25 },
contact: { email: 'zhangsan@example.com', phone: '138-0013-8000' }
},
preferences: {
theme: 'dark',
language: 'zh-CN'
}
}
};
console.dir(complexObject, { depth: null });
}
advancedConsoleUsage();
// 2. 调试器和断点
function debuggerUsage() {
console.log('=== 调试器使用 ===');
function calculateSum(numbers) {
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
// 在开发者工具中,这里会暂停执行
// debugger;
sum += numbers[i];
// 条件断点示例
if (sum > 100) {
console.log('总和超过100:', sum);
// debugger; // 只有当sum > 100时才暂停
}
}
return sum;
}
const numbers = [10, 20, 30, 40, 50];
const result = calculateSum(numbers);
console.log('计算结果:', result);
}
debuggerUsage();
// 3. 性能监控
class PerformanceMonitor {
static measure(name, fn) {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${name} 执行时间: ${(end - start).toFixed(2)}ms`);
return result;
}
static async measureAsync(name, asyncFn) {
const start = performance.now();
const result = await asyncFn();
const end = performance.now();
console.log(`${name} 执行时间: ${(end - start).toFixed(2)}ms`);
return result;
}
static profile(name, fn, iterations = 1000) {
const times = [];
for (let i = 0; i < iterations; i++) {
const start = performance.now();
fn();
const end = performance.now();
times.push(end - start);
}
const avg = times.reduce((sum, time) => sum + time, 0) / times.length;
const min = Math.min(...times);
const max = Math.max(...times);
console.log(`${name} 性能分析 (${iterations}次):`);
console.log(` 平均: ${avg.toFixed(4)}ms`);
console.log(` 最小: ${min.toFixed(4)}ms`);
console.log(` 最大: ${max.toFixed(4)}ms`);
return { avg, min, max, times };
}
static memoryUsage() {
if (performance.memory) {
const memory = performance.memory;
console.log('内存使用情况:');
console.log(` 已用: ${(memory.usedJSHeapSize / 1024 / 1024).toFixed(2)}MB`);
console.log(` 总计: ${(memory.totalJSHeapSize / 1024 / 1024).toFixed(2)}MB`);
console.log(` 限制: ${(memory.jsHeapSizeLimit / 1024 / 1024).toFixed(2)}MB`);
return memory;
} else {
console.log('浏览器不支持内存监控');
return null;
}
}
}
// 使用性能监控
function demonstratePerformanceMonitoring() {
console.log('=== 性能监控演示 ===');
// 测量同步函数
PerformanceMonitor.measure('数组创建', () => {
return Array.from({ length: 10000 }, (_, i) => i * 2);
});
// 测量异步函数
PerformanceMonitor.measureAsync('异步延迟', async () => {
await new Promise(resolve => setTimeout(resolve, 100));
return '完成';
});
// 性能分析
PerformanceMonitor.profile('字符串拼接', () => {
let str = '';
for (let i = 0; i < 100; i++) {
str += 'a';
}
return str;
}, 1000);
PerformanceMonitor.profile('数组join', () => {
const arr = new Array(100).fill('a');
return arr.join('');
}, 1000);
// 内存使用
PerformanceMonitor.memoryUsage();
}
demonstratePerformanceMonitoring();
// 4. 错误监控和报告
class ErrorReporter {
constructor() {
this.errors = [];
this.setupGlobalErrorHandling();
}
setupGlobalErrorHandling() {
// 捕获未处理的错误
window.addEventListener('error', (event) => {
this.reportError({
type: 'javascript',
message: event.message,
filename: event.filename,
lineno: event.lineno,
colno: event.colno,
error: event.error,
timestamp: new Date().toISOString()
});
});
// 捕获未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
this.reportError({
type: 'promise',
message: event.reason?.message || '未处理的Promise拒绝',
reason: event.reason,
timestamp: new Date().toISOString()
});
});
}
reportError(errorInfo) {
this.errors.push(errorInfo);
console.error('错误报告:', errorInfo);
// 在实际应用中,这里会发送到错误监控服务
this.sendToErrorService(errorInfo);
}
sendToErrorService(errorInfo) {
// 模拟发送到错误监控服务
console.log('发送错误到监控服务:', {
...errorInfo,
userAgent: navigator.userAgent,
url: window.location.href,
userId: this.getCurrentUserId()
});
}
getCurrentUserId() {
// 模拟获取当前用户ID
return 'user_123';
}
getErrorSummary() {
const summary = {
total: this.errors.length,
byType: {},
recent: this.errors.slice(-5)
};
this.errors.forEach(error => {
summary.byType[error.type] = (summary.byType[error.type] || 0) + 1;
});
return summary;
}
clearErrors() {
this.errors = [];
}
}
// 使用错误报告器
const errorReporter = new ErrorReporter();
// 模拟一些错误
setTimeout(() => {
// 这会触发全局错误处理
// throw new Error('模拟的JavaScript错误');
}, 1000);
setTimeout(() => {
// 这会触发未处理的Promise拒绝
Promise.reject(new Error('模拟的Promise错误'));
}, 2000);
setTimeout(() => {
console.log('错误摘要:', errorReporter.getErrorSummary());
}, 3000);
日志系统
// 完整的日志系统实现
class Logger {
constructor(options = {}) {
this.level = options.level || 'info';
this.prefix = options.prefix || '';
this.outputs = options.outputs || [new ConsoleOutput()];
this.formatters = options.formatters || [new DefaultFormatter()];
this.levels = {
error: 0,
warn: 1,
info: 2,
debug: 3,
trace: 4
};
}
log(level, message, ...args) {
if (this.levels[level] <= this.levels[this.level]) {
const logEntry = {
level,
message,
args,
timestamp: new Date(),
prefix: this.prefix
};
this.outputs.forEach(output => {
this.formatters.forEach(formatter => {
const formatted = formatter.format(logEntry);
output.write(formatted);
});
});
}
}
error(message, ...args) {
this.log('error', message, ...args);
}
warn(message, ...args) {
this.log('warn', message, ...args);
}
info(message, ...args) {
this.log('info', message, ...args);
}
debug(message, ...args) {
this.log('debug', message, ...args);
}
trace(message, ...args) {
this.log('trace', message, ...args);
}
child(prefix) {
return new Logger({
level: this.level,
prefix: this.prefix ? `${this.prefix}:${prefix}` : prefix,
outputs: this.outputs,
formatters: this.formatters
});
}
}
// 格式化器
class DefaultFormatter {
format(logEntry) {
const timestamp = logEntry.timestamp.toISOString();
const level = logEntry.level.toUpperCase().padEnd(5);
const prefix = logEntry.prefix ? `[${logEntry.prefix}] ` : '';
return {
timestamp,
level,
message: `${timestamp} ${level} ${prefix}${logEntry.message}`,
args: logEntry.args
};
}
}
class JSONFormatter {
format(logEntry) {
return {
timestamp: logEntry.timestamp.toISOString(),
level: logEntry.level,
prefix: logEntry.prefix,
message: logEntry.message,
args: logEntry.args
};
}
}
// 输出器
class ConsoleOutput {
write(formatted) {
const method = this.getConsoleMethod(formatted.level);
if (formatted.args && formatted.args.length > 0) {
console[method](formatted.message, ...formatted.args);
} else {
console[method](formatted.message);
}
}
getConsoleMethod(level) {
switch (level.toLowerCase().trim()) {
case 'error': return 'error';
case 'warn': return 'warn';
case 'debug': return 'debug';
case 'trace': return 'trace';
default: return 'log';
}
}
}
class MemoryOutput {
constructor(maxEntries = 1000) {
this.entries = [];
this.maxEntries = maxEntries;
}
write(formatted) {
this.entries.push(formatted);
if (this.entries.length > this.maxEntries) {
this.entries.shift();
}
}
getEntries(level = null) {
if (level) {
return this.entries.filter(entry =>
entry.level.toLowerCase().trim() === level.toLowerCase()
);
}
return [...this.entries];
}
clear() {
this.entries = [];
}
}
class RemoteOutput {
constructor(endpoint, batchSize = 10, flushInterval = 5000) {
this.endpoint = endpoint;
this.batchSize = batchSize;
this.flushInterval = flushInterval;
this.buffer = [];
// 定期刷新缓冲区
setInterval(() => this.flush(), flushInterval);
// 页面卸载时刷新
window.addEventListener('beforeunload', () => this.flush());
}
write(formatted) {
this.buffer.push(formatted);
if (this.buffer.length >= this.batchSize) {
this.flush();
}
}
async flush() {
if (this.buffer.length === 0) return;
const logs = [...this.buffer];
this.buffer = [];
try {
await fetch(this.endpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ logs })
});
} catch (error) {
console.error('发送日志失败:', error);
// 失败的日志重新加入缓冲区
this.buffer.unshift(...logs);
}
}
}
// 使用日志系统
function demonstrateLoggingSystem() {
console.log('=== 日志系统演示 ===');
// 创建内存输出器用于演示
const memoryOutput = new MemoryOutput();
// 创建主日志器
const logger = new Logger({
level: 'debug',
outputs: [new ConsoleOutput(), memoryOutput],
formatters: [new DefaultFormatter()]
});
// 基本日志
logger.info('应用启动');
logger.debug('调试信息', { userId: 123, action: 'login' });
logger.warn('警告:内存使用率较高', { usage: '85%' });
logger.error('错误:数据库连接失败', new Error('连接超时'));
// 创建子日志器
const userLogger = logger.child('UserService');
const dbLogger = logger.child('Database');
userLogger.info('用户登录', { userId: 123, username: 'zhangsan' });
userLogger.debug('验证用户权限');
dbLogger.warn('查询执行缓慢', { query: 'SELECT * FROM users', duration: '2.5s' });
dbLogger.error('连接池耗尽');
// 查看内存中的日志
console.log('\n内存中的所有日志:');
memoryOutput.getEntries().forEach(entry => {
console.log(entry.message);
});
console.log('\n只显示错误日志:');
memoryOutput.getEntries('error').forEach(entry => {
console.log(entry.message);
});
}
demonstrateLoggingSystem();
// 日志分析工具
class LogAnalyzer {
constructor(memoryOutput) {
this.memoryOutput = memoryOutput;
}
getStatistics() {
const entries = this.memoryOutput.getEntries();
const stats = {
total: entries.length,
byLevel: {},
byPrefix: {},
timeRange: null
};
if (entries.length > 0) {
const timestamps = entries.map(e => new Date(e.timestamp));
stats.timeRange = {
start: new Date(Math.min(...timestamps)),
end: new Date(Math.max(...timestamps))
};
}
entries.forEach(entry => {
const level = entry.level.toLowerCase().trim();
stats.byLevel[level] = (stats.byLevel[level] || 0) + 1;
// 从消息中提取前缀
const prefixMatch = entry.message.match(/\[([^\]]+)\]/);
if (prefixMatch) {
const prefix = prefixMatch[1];
stats.byPrefix[prefix] = (stats.byPrefix[prefix] || 0) + 1;
}
});
return stats;
}
findErrors() {
return this.memoryOutput.getEntries('error');
}
findPattern(pattern) {
const regex = new RegExp(pattern, 'i');
return this.memoryOutput.getEntries().filter(entry =>
regex.test(entry.message)
);
}
getRecentLogs(minutes = 5) {
const cutoff = new Date(Date.now() - minutes * 60 * 1000);
return this.memoryOutput.getEntries().filter(entry =>
new Date(entry.timestamp) > cutoff
);
}
}
本章总结
本章全面介绍了JavaScript的错误处理与调试:
- 错误类型和异常处理:学习了JavaScript中的各种错误类型、try-catch-finally语句和自定义错误类型
- 异步错误处理:掌握了Promise和async/await中的错误处理机制,以及重试和超时控制
- 调试技巧和工具:了解了浏览器调试工具的高级用法、性能监控和错误报告
- 日志系统:学习了如何构建完整的日志系统,包括格式化器、输出器和日志分析
良好的错误处理和调试能力是JavaScript开发者的重要技能。通过合理的错误处理策略、有效的调试技巧和完善的日志系统,我们可以构建更加健壮和可维护的应用程序。
至此,JavaScript教程的核心内容已经完成。这些知识涵盖了从基础语法到高级特性的各个方面,为深入学习和实际开发奠定了坚实的基础。