JavaScript中的异步错误处理与Promise链的错误传播
字数 472 2025-11-26 11:34:09

JavaScript中的异步错误处理与Promise链的错误传播

在JavaScript异步编程中,错误处理是一个关键课题。与同步代码使用try-catch不同,异步操作中的错误需要通过特定机制进行捕获和处理。

1. 异步错误处理的基本挑战

// 同步错误可以正常捕获
try {
  throw new Error('同步错误');
} catch (error) {
  console.log('捕获到:', error.message); // 正常捕获
}

// 异步错误无法用try-catch捕获
try {
  setTimeout(() => {
    throw new Error('异步错误');
  }, 0);
} catch (error) {
  console.log('这行不会执行'); // 无法捕获异步错误
}

原因:异步操作会被放入任务队列,当错误发生时,同步的try-catch块已经执行完毕。

2. Promise的错误处理机制
Promise提供了专门的错误处理方式:

// 方式1:使用catch方法
fetch('/api/data')
  .then(response => response.json())
  .then(data => console.log(data))
  .catch(error => {
    console.log('捕获Promise链中的错误:', error);
  });

// 方式2:then的第二个参数(不推荐,有局限性)
fetch('/api/data')
  .then(
    response => response.json(),
    error => console.log('只能捕获当前then的错误:', error)
  );

3. Promise链的错误传播特性
Promise链具有"冒泡"特性,错误会一直向后传递,直到被catch捕获:

function asyncOperation() {
  return new Promise((resolve, reject) => {
    Math.random() > 0.5 ? resolve('成功') : reject(new Error('操作失败'));
  });
}

asyncOperation()
  .then(result => {
    console.log('第一步:', result);
    return asyncOperation(); // 可能再次失败
  })
  .then(result => {
    console.log('第二步:', result);
    return '所有操作完成';
  })
  .catch(error => {
    console.log('捕获整个链路的错误:', error.message);
    return '降级结果';
  })
  .then(finalResult => {
    console.log('最终结果:', finalResult);
  });

4. 错误处理的实践技巧

// 技巧1:在catch中返回正常值,让链条继续
fetch('/api/main')
  .catch(error => {
    console.log('主API失败,使用备用数据');
    return { data: '备用数据' };
  })
  .then(data => processData(data));

// 技巧2:重新抛出错误
fetch('/api/data')
  .then(response => {
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    return response.json();
  })
  .catch(error => {
    if (error.message.includes('404')) {
      // 处理特定错误
      return { data: [] };
    }
    // 其他错误继续抛出
    throw error;
  })
  .catch(error => {
    console.log('最终错误处理:', error);
  });

5. async/await中的错误处理
async函数提供了更直观的错误处理方式:

// 方式1:try-catch(推荐)
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    const data = await response.json();
    return data;
  } catch (error) {
    console.log('捕获async函数错误:', error);
    throw error; // 可以继续抛出
  }
}

// 方式2:在调用处使用catch
fetchData()
  .then(data => console.log(data))
  .catch(error => console.log('外部捕获:', error));

// 方式3:Promise.all的错误处理
async function fetchMultiple() {
  try {
    const [user, posts] = await Promise.all([
      fetch('/api/user'),
      fetch('/api/posts')
    ]);
    return { user, posts };
  } catch (error) {
    // 任何一个Promise被拒绝都会进入catch
    console.log('多个请求中有错误:', error);
  }
}

6. 未处理错误的全局捕获

// 浏览器环境
window.addEventListener('unhandledrejection', event => {
  console.log('未处理的Promise拒绝:', event.reason);
  event.preventDefault(); // 阻止默认错误输出
});

// Node.js环境
process.on('unhandledRejection', (reason, promise) => {
  console.log('未处理的Promise拒绝:', reason);
});

关键要点总结:

  • Promise错误具有冒泡特性,会向后传递直到被捕获
  • catch方法应该放在链条末尾来捕获所有错误
  • async/await可以使用try-catch,但返回的仍是Promise
  • 重要的错误应该重新抛出,让调用方知晓
  • 始终设置全局未处理错误监听,避免静默失败
JavaScript中的异步错误处理与Promise链的错误传播 在JavaScript异步编程中,错误处理是一个关键课题。与同步代码使用try-catch不同,异步操作中的错误需要通过特定机制进行捕获和处理。 1. 异步错误处理的基本挑战 原因:异步操作会被放入任务队列,当错误发生时,同步的try-catch块已经执行完毕。 2. Promise的错误处理机制 Promise提供了专门的错误处理方式: 3. Promise链的错误传播特性 Promise链具有"冒泡"特性,错误会一直向后传递,直到被catch捕获: 4. 错误处理的实践技巧 5. async/await中的错误处理 async函数提供了更直观的错误处理方式: 6. 未处理错误的全局捕获 关键要点总结: Promise错误具有冒泡特性,会向后传递直到被捕获 catch方法应该放在链条末尾来捕获所有错误 async/await可以使用try-catch,但返回的仍是Promise 重要的错误应该重新抛出,让调用方知晓 始终设置全局未处理错误监听,避免静默失败