image.png
performSyncWorkOnRoot 开启 render 阶段
commitRoot 开启 commit 阶段

初始化阶段

image.png
这阶段的目的是:
完成 Fiber 基本实体的创建
image.png
current 属性:
FiberNode 是 Fiber 节点对应的对象类型
image.png
image.png

  • fiberRoot 是真实 DOM 的容器节点
  • rootFiber 是虚拟 DOM 的根节点

    初始化的行为:

    image.png
    unbatchedUpdates 直接调用传入的回调 fn,fn 是针对 updateContainer 的调用,主要做了三件事

  • 请求当前 Fiber 节点的 lane(优先级)

  • 结合 lane 创建当前 Fiber 节点为的 update 对象,并将其入队
  • 调度当前节点(rootFiber) :::info 在 ReactDOM.render 发起前的前次渲染链路中,这些意义都不大,国灰这个渲染过程其实是同步的 ::: 因为会跑到 performSyncWorkOnRoot

  • performSyncWorkOnRoot 是 render 阶段的起点,render 阶段是任务就是完成构建 Fiber 树

    为何 ReactDOM.render 触发的首次渲染是个同步的过程呢?

    因为目前的 React16 / 17 都会有三种模式:

  • legacy ReactDOM.render(<App />, rootNode);

  • blocking ReactDOM.createBlockingRoot(rootNode).render(<App />);
    • 作为迁移至 concurrent 的第一个步骤
  • concurrent ReactDOM.createRoot(rootNode).render(<App />);

这个 React 官方想提供渐进的迁移方式,长远来看模式的数量会收敛,不考虑不同的模式

mode 属性会决定工作流是同步还是异步

Fiber 架构一定是异步渲染吗?

从动机上看,Fiber 架构的设计确实是为了 Concurrent 存在,Fiber 架构在 React 中并不能和异步渲染画严格等号。
它是一种同时兼容了同步渲染与异步渲染的设计

render 阶段

React15 下的调和过程是一个递归的过程,在 ReactDOM.render 触发同步模式下仍然是一个深度优先搜索过程

  • beginWork 将创建新的 Fiber 节点
  • completeWork 负责将 Fiber 节点为映射为 DOM 节点

    prepareFreshStack 重置一个新的对象环境

  • createWorkInProgress 调用 createFiber
    workInProgress 是 createFiber 方法的返回值

    • FiberNode 类型
    • workInProgress 节点是 current 节点(rootFiber)的副本
  • workInProgress 的 alternate 将指向 current
  • current 的 alternate 反过来指向 workInProgress

image.png

完成之后会进入 workLoopSync

  • 通过 while 反复判断 workInProgress 是否为空
  • performUnitOfWork 触发对 beginWork 的调用,进而实现对新 Fiber 节点的创建
    • beginWork 的入参是一对 alternate 连接起来的 workInprogress 和 current 节点
    • beginWork 的核心逻辑是根据 fiber 节点(workInProgress)的 tag 属性的不同调用不同的节点创建函数
      • 这些创建函数都会通过 reconcileChildren 方法,生成当前节点的子点image.png
        image.png
        • reconcileChildeFibers 和 mounChildFibers 的不同,在于对副作用的处理不同
        • ChildReconciler 中定义大量如 placeXXX、deleteXXX、updateXXX、reconcileXXX 函数
          • 覆盖对 Fiber 节点的创建、增加、删除、修改,直接或间接被 reconcileChildFibers 所调用
        • ChildReconciler 返回一个 reconcileChildFibers 的函数
          • 逻辑分发器,根据入参不同,执行不同的 Fiber 节点操作,返回不同的目标 Fiber 节

image.png
image.png
image.png

不同的 Fiber 节点将通过 child、return、sibling 建立关系

  • child、return 记录父子节点关系
  • sibling 记录兄弟节点关系

image.png
image.png

completeWork 工作原理

工作内容:负责处理 Fiber 节点到 DOM 节点的映射逻辑
3 个关键动作:

  1. 创建 DOM 节点(CreateInstance)
  2. 将 DOM 节点插入到 DOM 树中(AppendAllChildren)
  3. 为 DOM 节点设置属性(FinalizeInitialChildren)

创建好的 DOM 节点会被赋值给 workInProgress 节点的 stateNode 属性
将 DOM 节点插入到 DOM 树的操作是通过 appendAllChildren 函数完成

  • 实际上是将子 Fiber 节点所对应的 DOM 节点挂载其父 Fiber 节点所对应的 DOM 节点

    completeUnitOfWork 开启收集 EffectList 大循环

    针对传入的当前节点,调用 completeWork
    将当前节点的副作用链插入到其父节点对应的副作用链中
    以当前节点为起点,循环遍历其兄弟节点及其父节点

    render 阶段的工作目标

    找出界面中需要处理的更新

    副作用链 effectList

    render 阶段“工作成果”的一个集合

  • 都是当前 Fiber 节点的后代节点

  • 都有待处理的副作用

Fiber 节点的 effectList 里记录是其需要更新的后代节点

将当前节点的副作用链插入到其父节点对应的副作用链中

completeWork 是自底向上执行的,所以子节点的 completeWork 总是比父节点先执行

把所有需要更新的 Fiber 节点单独串成一串链表,方便后续有针对性地对进行更新,这就是“收集副作用”过程

  • App FiberNode 的 flags 属性为 3,大于 PerformedWork
    因些会进入 effectList 的创建逻辑
  • 创建 effectList 时,并不是为当前 Fiber 节点创建,而为它的父节点创建
    App 节点的父节点是 rootFiber,rootFiber 的 effectList 此时为空
  • rootFiber 的 firstEffect 和 lastEffect 揭地都会指向 App 节点
    App 节点由此成为 effectList 中唯一一个 FiberNode

image.png

commit 阶段

只负责实现更新,而不负责寻找更新

  • before mutation 阶段 DOM 节点还没有被渲染到界面
  • mutation 负责 DOM 节点的渲染
  • layout 处理 DOM 渲染完毕之后的收尾逻辑
    还会把 fiberRoot 的 current 指针指向 workInProgress Fiber 树