前端一面:错误处理与全局异常捕获

很多一面会从“你遇到过哪些线上错误、怎么处理的?”切到错误处理这一块。这一篇从同步/异步错误处理、全局异常捕获以及在框架里的做法三个角度梳理一下,并给出几道常见题的参考答案。

在浏览器中,错误大致可以分为:

  • 同步错误:在当前调用栈中抛出的异常,例如访问未定义变量、手动 throw 等;
  • 异步错误:发生在回调、Promise、事件处理等异步路径中的错误。

同步错误可以用 try/catch 捕获:

1try {
2  riskyOperation();
3} catch (e) {
4  console.error("同步错误", e);
5}

异步错误的处理则依赖各自机制:

  • 回调风格:在回调参数中约定 error
  • Promise:使用 .catch 捕获链路上的错误;
  • async/await:外层用 try/catch 包裹 await

典型示例:

1async function main() {
2  try {
3    const res = await fetch("/api");
4    const data = await res.json();
5  } catch (e) {
6    console.error("请求失败", e);
7  }
8}

一面里能把这几个层次说清楚,基本就能展示你对错误处理模型的理解。

除了局部的 try/catch,很多项目会在入口处做全局异常捕获,用于监控/兜底展示:

  • window.onerror:捕获未被 try/catch 捕获的运行时错误;
  • window.onunhandledrejection:捕获未被显式 .catch 处理的 Promise 拒绝。

示例:

1window.onerror = function (message, source, lineno, colno, error) {
2  // 上报错误信息
3  console.log("全局错误", { message, source, lineno, colno, error });
4};
5
6window.onunhandledrejection = function (event) {
7  console.log("未处理的 Promise 拒绝", event.reason);
8};

注意:

  • 这些全局处理更适合作“监控 + 兜底提示”,而不是在其中写复杂业务逻辑;
  • 对于跨域脚本,如果未正确设置 crossorigin 和服务器 Access-Control-Allow-Originonerror 得到的信息可能被限制(只显示 “Script error.”)。

在框架中,通常会提供一套更高层的错误处理机制,例如 React 的 Error Boundary:

 1class ErrorBoundary extends React.Component {
 2  state = { hasError: false };
 3
 4  static getDerivedStateFromError(error) {
 5    return { hasError: true };
 6  }
 7
 8  componentDidCatch(error, info) {
 9    // 上报错误
10    console.error("组件错误", error, info);
11  }
12
13  render() {
14    if (this.state.hasError) {
15      return <div>出错了,请稍后再试。</div>;
16    }
17    return this.props.children;
18  }
19}

通过在关键 UI 区域外包一层 Error Boundary,可以:

  • 防止单个组件错误导致整个应用白屏;
  • 在组件层级捕获错误并上报;
  • 给用户一个较为友好的兜底文案。

一面如果涉及 React/Vue,可以简单提一下组件层的错误边界概念。

参考答案要点:

  • 同步错误可以直接用 try/catch 捕获;
  • 异步错误需要跟随异步抽象:
    • Promise 使用 .catch 或在 async/await 外层用 try/catch
    • 事件/回调风格通过错误参数或统一封装处理;
  • 单纯的 try/catch 无法捕获已经进入事件循环的异步回调里的错误。

可以补一句:

“我们会在异步入口处尽量统一封装,比如封装 request 方法,在内部统一处理错误和重试逻辑。”

参考答案要点:

  • 可以通过 window.onerror 捕获未处理的运行时错误,通过 window.onunhandledrejection 捕获未处理的 Promise 拒绝;
  • 这些全局钩子适合用来做错误监控和兜底提示;
  • 局限包括:
    • 无法精确区分错误上下文,堆栈可能被压缩/混淆;
    • 对跨域脚本,如果未正确设置 CORS 与 crossorigin,错误信息会受限。

参考答案要点:

  • 可以使用 Error Boundary,在关键组件外层包一层错误边界组件;
  • Error Boundary 可以在子组件抛错时捕获错误,渲染兜底 UI,并在 componentDidCatch 中上报错误;
  • 需要注意的是,它只能捕获渲染/生命周期中的错误,无法捕获事件处理器内同步抛出的错误(需要配合其它机制)。

这种问法既考你对错误处理的理解,也考察你对框架内建机制的熟悉程度。