错误处理

在JavaScript中,错误处理是确保程序在遇到异常情况时能够优雅地处理并继续运行的重要机制。

错误类型

JavaScript有多种内置错误类型:

Error

所有错误类型的父类,可用于创建自定义错误:

javascript
const customError = new Error('这是一个自定义错误');

SyntaxError

语法错误,当代码语法不正确时抛出:

javascript
// 语法错误:缺少右括号
console.log('Hello world';

ReferenceError

引用错误,当尝试访问不存在的变量时抛出:

javascript
// 引用错误:x未定义
console.log(x);

TypeError

类型错误,当变量或参数的类型不正确时抛出:

javascript
// 类型错误:数字没有length属性
const num = 123;
console.log(num.length);

RangeError

范围错误,当值超出有效范围时抛出:

javascript
// 范围错误:数组长度不能为负数
const arr = new Array(-1);

URIError

URI错误,当URI相关函数的参数不正确时抛出:

javascript
// URI错误:解码无效的URI
decodeURIComponent('%');

EvalError

eval错误,当eval()函数执行出错时抛出(在现代JavaScript中很少使用)。

try/catch/finally语句

try

包含可能抛出错误的代码块:

javascript
try {
  // 可能出错的代码
  const result = riskyOperation();
  console.log(result);
} catch (error) {
  // 错误处理代码
  console.error('发生错误:', error.message);
}

catch

包含处理错误的代码块,接收一个错误对象参数:

javascript
try {
  // 可能出错的代码
} catch (error) {
  console.error('错误类型:', error.name);
  console.error('错误消息:', error.message);
  console.error('错误堆栈:', error.stack);
}

finally

无论是否发生错误,都会执行的代码块:

javascript
try {
  // 可能出错的代码
} catch (error) {
  // 错误处理
} finally {
  // 清理代码
  console.log('无论是否出错,都会执行');
}

throw语句

手动抛出错误:

javascript
function divide(a, b) {
  if (b === 0) {
    throw new Error('除数不能为零');
  }
  return a / b;
}

try {
  const result = divide(10, 0);
  console.log(result);
} catch (error) {
  console.error(error.message); // '除数不能为零'
}

自定义错误

可以通过继承Error类来创建自定义错误类型:

javascript
class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = 'ValidationError';
  }
}

function validateUser(user) {
  if (!user.name) {
    throw new ValidationError('用户名不能为空');
  }
  if (!user.email) {
    throw new ValidationError('邮箱不能为空');
  }
  return true;
}

try {
  validateUser({ name: 'John' });
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('验证失败:', error.message);
  } else {
    console.error('其他错误:', error.message);
  }
}

错误处理最佳实践

1. 只捕获预期的错误

避免捕获所有错误,只捕获你能处理的错误:

javascript
try {
  // 可能出错的代码
} catch (error) {
  if (error instanceof ValidationError) {
    // 处理验证错误
  } else if (error instanceof NetworkError) {
    // 处理网络错误
  } else {
    // 重新抛出未知错误
    throw error;
  }
}

2. 提供有用的错误信息

错误信息应该清晰、具体,有助于调试:

javascript
// 不好
if (!user.name) throw new Error('错误');

// 好
if (!user.name) throw new Error('用户名不能为空');

3. 记录错误

在生产环境中,应该记录错误以便分析:

javascript
try {
  // 可能出错的代码
} catch (error) {
  console.error('发生错误:', error);
  // 发送错误到日志服务器
  logErrorToServer(error);
}

4. 优雅降级

当发生错误时,提供备用功能:

javascript
function fetchData() {
  return fetch('https://api.example.com/data')
    .then(response => response.json())
    .catch(error => {
      console.error('数据获取失败:', error);
      // 返回默认数据
      return { data: [], error: true };
    });
}

5. 使用Promise的catch

处理Promise链中的错误:

javascript
fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => console.error('错误:', error));

6. 使用async/await的try/catch

处理async/await中的错误:

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

全局错误处理

window.onerror

捕获全局JavaScript错误:

javascript
window.onerror = function(message, source, lineno, colno, error) {
  console.error('全局错误:', { message, source, lineno, colno, error });
  // 阻止默认错误处理
  return true;
};

window.addEventListener(‘error’)

使用事件监听器捕获全局错误:

javascript
window.addEventListener('error', function(event) {
  console.error('全局错误:', event.error);
});

window.addEventListener(‘unhandledrejection’)

捕获未处理的Promise拒绝:

javascript
window.addEventListener('unhandledrejection', function(event) {
  console.error('未处理的Promise拒绝:', event.reason);
  // 阻止默认错误处理
  event.preventDefault();
});

学习资源


继续学习:闭包

最后更新:2026-02-08