错误捕获
# 错误捕获
React 提供了两个 API 进行错误捕获:
getDerivedStateFromError
静态方法,保存在 fiberNode.type 上。用于渲染 fallback UI,需要返回一个 state,
componentDidCatch
组件实例方法,保存在组件实例(fiber.stateNode)上。 用于执行副作用代码(如上报等)
这两个方法只能在类组件中使用,只能捕获子组件中的错误(组件自身的不行),使用了这两个方法的组件成为错误边界(Error boundaries)。
捕获的过程分为三步:
- 捕获错误
- 构造 callback
- 执行 callback
# 捕获范围
Error boundaries 捕获的是 render 阶段和 commit 阶段的错误
不会被捕获的四类错误:
- 回调函数中的错误
- 异步代码中的错误
- SSR 中的错误
- Error boundaries 组件中出现的错误
# 捕获错误
根据当前流程的不同,会交由不同的回调函数处理。
- render 阶段:
handleError
- commit 阶段:
captureCommitPhaseError
然后都会交给 captureCommitPhaseError
方法处理
# 构造 callback
从发生异常的 fiberNode 的父节点开始,向上寻找 Error boundaries。
- 若找到,会执行
createClassErrorUpdate
方法构造 update 对象,它的属性是待执行的回调- payload:执行
getDerivedStateFromError
- callback:抛出 React 提示信息,执行
componentDidCatch
- payload:执行
- 若没有找到,会构造 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 {
//
}
2
3
4
5
6
7
8
9
# Suspense wakeable
- 首先会重置 Suspense 的状态,将其 state 恢复到本次渲染之前。
- 通过
getSuspenseHandler
返回寻找 suspense 的错误边界 fiber - 如果找到,判断当前元素是否是离屏元素,如果是离屏元素则只在 concurrent 模式才处理,sync 模式不处理。
- 添加重新渲染的监听:将捕获到的 Promise 加入 fiber 节点的
updateQueue
。如果后续这个 Promise 变为 resolve,则会重新渲染 Suspense
- 添加重新渲染的监听:将捕获到的 Promise 加入 fiber 节点的
- 如果找不到,判断是否是同步更新
- 如果是同步更新,属于异常,会抛出一个 Error
- 如果不是同步更新,则也会添加重新渲染的监听
# 非 Suspense wakeable
构造出的 update 对象,会交由 enqueueCapturedUpdate
处理,将 update
添加到 fiber 对应的 updateQueue
中
如果 commit
执行 callback 的时机有两个