错误捕获

Youky ... 2025-2-19 前端
  • React
About 2 min

# 错误捕获

React 提供了两个 API 进行错误捕获:

  • getDerivedStateFromError

静态方法,保存在 fiberNode.type 上。用于渲染 fallback UI,需要返回一个 state,

  • componentDidCatch

组件实例方法,保存在组件实例(fiber.stateNode)上。 用于执行副作用代码(如上报等)

这两个方法只能在类组件中使用,只能捕获子组件中的错误(组件自身的不行),使用了这两个方法的组件成为错误边界(Error boundaries)。

捕获的过程分为三步:

  1. 捕获错误
  2. 构造 callback
  3. 执行 callback

# 捕获范围

Error boundaries 捕获的是 render 阶段和 commit 阶段的错误

不会被捕获的四类错误:

  • 回调函数中的错误
  • 异步代码中的错误
  • SSR 中的错误
  • Error boundaries 组件中出现的错误

# 捕获错误

根据当前流程的不同,会交由不同的回调函数处理。

  • render 阶段:handleError
  • commit 阶段:captureCommitPhaseError

然后都会交给 captureCommitPhaseError 方法处理

# 构造 callback

从发生异常的 fiberNode 的父节点开始,向上寻找 Error boundaries。

  • 若找到,会执行 createClassErrorUpdate 方法构造 update 对象,它的属性是待执行的回调
    • payload:执行 getDerivedStateFromError
    • callback:抛出 React 提示信息,执行 componentDidCatch
  • 若没有找到,会构造 callback,内部抛出“未捕获的错误”以及 React 提示信息

# 执行 callback

# render 阶段

handleError 会将 相关信息交给 throwException 方法处理

首先判断是否是 Promise 类型(Suspense wakeable Error),并根据结果做不同处理

TODO: Suspense wakeable 是什么?

if (
  value !== null &&
  typeof value === "object" &&
  typeof value.then === "function"
) {
  // 处理 suspense 场景
} else {
  //
}
1
2
3
4
5
6
7
8
9

# Suspense wakeable

  • 首先会重置 Suspense 的状态,将其 state 恢复到本次渲染之前。
  • 通过 getSuspenseHandler 返回寻找 suspense 的错误边界 fiber
  • 如果找到,判断当前元素是否是离屏元素,如果是离屏元素则只在 concurrent 模式才处理,sync 模式不处理。
    • 添加重新渲染的监听:将捕获到的 Promise 加入 fiber 节点的 updateQueue。如果后续这个 Promise 变为 resolve,则会重新渲染 Suspense
  • 如果找不到,判断是否是同步更新
    • 如果是同步更新,属于异常,会抛出一个 Error
    • 如果不是同步更新,则也会添加重新渲染的监听

# 非 Suspense wakeable

构造出的 update 对象,会交由 enqueueCapturedUpdate 处理,将 update 添加到 fiber 对应的 updateQueue

如果 commit

执行 callback 的时机有两个

Last update: February 19, 2025 22:47
Contributors: Youky1