乐趣区

关于java:Error-Boundaries是这么实现的还挺巧妙

一张图概括:

这里简略解说下 React 工作流程,后文有用。分为三步:

触发更新
render 阶段:计算更新会造成的副作用
commit 阶段:在宿主环境执行副作用
副作用有很多,比方:

插入 DOM 节点
执行 useEffect 回调
好了,让咱们进入主题。

什么是 Error Boundaries
React 提供了两个与错误处理相干的 API:

getDerivedStateFromError:静态方法,当谬误产生后提供一个机会渲染 fallback UI
componentDidCatch:组件实例办法,当谬误产生后提供一个机会记录错误信息
应用了这两个 API 的 ClassComponent 通常被称为 Error Boundaries(谬误边界)。

在 Error Boundaries 的子孙组件中产生的所有 React 工作流程内的谬误都会被 Error Boundaries 捕捉。

通过开篇的介绍能够晓得,React 工作流程指:

render 阶段
commit 阶段
思考如下代码:

class ErrorBoundary extends Component {
componentDidCatch(e) {

console.warn(“产生谬误”, e);

}
render() {

return <div>{this.props.children}</div>;

}
}

const App = () => (

<ErrorBoundary>
<A><B/></A>
<C/>
<ErrorBoundary>

)
A、B、C 作为 ErrorBoundary 的子孙组件,当产生 React 工作流程内的谬误,都会被 ErrorBoundary 中的 componentDidCatch 办法捕捉。

步骤 1: 捕捉谬误
首先来看工作流程中的谬误都是何时被捕捉的。

render 阶段的外围代码如下,产生的谬误会被 handleError 解决:

do {
try {

// 对于并发更新则是 workLoopConcurrent

workLoopSync();

break;

} catch (thrownValue) {

handleError(root, thrownValue);

}
} while (true);
commit 阶段蕴含很多工作,比方:

componentDidMount/Update 执行
绑定 / 解绑 ref
useEffect/useLayoutEffectcallback 与 destroy 执行
这些工作会以如下模式执行,产生的谬误被 captureCommitPhaseError 解决:

try {
// …执行某项工作
} catch (error) {
captureCommitPhaseError(fiber, fiber.return, error);
}
步骤 2: 结构 callback
能够发现,即便没有 Error Boundaries,工作流程中的谬误曾经被 React 捕捉了。而正确的逻辑应该是:

如果存在 Error Boundaries,执行对应 API
抛出 React 的提示信息
如果不存在 Error Boundaries,抛出未捕捉的谬误
所以,不论是 handleError 还是 captureCommitPhaseError,都会从产生谬误的节点的父节点开始,逐层向上遍历,寻找最近的 Error Boundaries。

一旦找到,就会结构:

用于执行 Error Boundaries API 的 callback
用于抛出 React 提示信息的 callback

// … 为了可读性,逻辑有删减
function createClassErrorUpdate() {
if (typeof getDerivedStateFromError === ‘function’) {
// 用于执行 getDerivedStateFromError 的 callback

update.payload = () => {return getDerivedStateFromError(error);

};
// 用于抛出 React 提示信息的 callback

update.callback = () => {logCapturedError(fiber, errorInfo);
};

}
if (inst !== null && typeof inst.componentDidCatch === ‘function’) {
// 用于执行 componentDidCatch 的 callback

update.callback = function callback() {this.componentDidCatch(error);
};

}
return update;
}
如果没有找到 Error Boundaries,持续向上遍历直到根节点。

此时会结构:

用于抛出未捕捉谬误的 callback
用于抛出 React 提示信息的 callback
// … 为了可读性,逻辑有删减
funffction createRootErrorUpdate() {
// 用于抛出“未捕捉的谬误”及“React 的提示信息”的 callback
update.callback = () => {

onUncaughtError(error);
logCapturedError(fiber, errorInfo);

};
return update;
}
执行 callback
结构好的 callback 在什么时候执行呢?

在 React 中有两个执行用户自定义 callback 的 API:

对于 ClassComponent,this.setState(newState, callback)中 newState 和 callback 参数都能传递 Function 作为 callback
所以,对于 Error Boundaries,相当于被动触发了一次更新:

this.setState(() => {
// 用于执行 getDerivedStateFromError 的 callback
}, () => {
// 用于执行 componentDidCatch 的 callback
// 以及 用于抛出 React 提示信息的 callback
})

退出移动版