Suspense 实现

- 在
beginWork时,遇到Suspense,默认是正常显示组件:创建一个OffScreenComponent来表示,此时visible为true。 - 当加载到组件内部的
promise时,由于第一次渲染,此时还未加载完成,会报错,抛出promise。 handleError捕捉到错误,首先开始throwException:- 标记报错的
fiber.flags为Incomplete。 - 向上查找,找到第一个
Suspense。 - 在
Suspense.updateQueue中添加报错信息(也就是抛出的promise)。 - 通过
attachPingListener方法执行该promise,并在then回调里添加一个更新任务。 - 标记
Suspense fiber flags为ShouldCapture。
- 标记报错的
- 从报错的
fiber开始,执行completeWork:- 向上找到
ShouldCapture的Suspense,标记为DidCapture。 - 查找过程中遇到的
fiber,标记为Incomplete。 - 返回最终的
fiber:Suspense或者HostRoot(没找到Suspense)。
- 向上找到
- 对找到的
Suspense重新开始beginWork。此时DidCapture为true,显示fallback。Suspense的child指向OffScreenComponent(内部包含主要的组件),OffScreenComponent的sibling指向fallbackChildFragment(占位组件)。而真正进行渲染的是fallbackChildFragment。 - 在
completeWork的时候,对于Suspense fiber,检测到已经从显示primary(主组件)变为显示fallback(占位组件)。如果此时updateQueue存在,说明还有待更新的任务,标记fiber为Update。 - 在
commitWork阶段,对于标记Update的Suspense,会调用attachSuspenseRetryListeners将所有异步任务的then添加更新任务,对应的lane为retryLane。(如果之前已经更新过了,那么不需要重复更新,这里只是作为保障) - 等到
promise加载完成,重新开始更新,此时就能正常的显示primary组件了。
