研究了React源码后知道的答案

宏观结构

以下代码源码均以 v18 版本来进行解说

参考图解 React-架构分层,可以把 react 整体结构分成以下两个核心层

  • react暴露的接口层
  • 调度器scheduler---构造器react-reconciler---渲染器react-dom组成的内核层

以下问题,是按照内核层三层架构的主干链路中核心源码进行解答,如果问题欢迎提出。

调度器 scheduler

核心职责只有一个,就是执行回调

  • 把 react-reconciler 提供的回调函数, 包装到一个任务对象中
  • 在内部维护一个任务队列, 优先级高的排在最前面
  • 循环消费任务队列, 直到队列清空

时间切片原理

时间切片(time slicing)的主要作用是执行时间分割,让出主线程(把控制权归还给浏览器,让浏览器可以处理用户输入、UI 绘制等紧急任务)

构造器 react-reconciler

主要功能分为以下四个阶段

  1. 输入: 暴露 api 函数(如: scheduleUpdateOnFiber), 供给其他包(如 react 包)调用
  2. 注册调度任务: 与调度中心(scheduler 包)交互, 注册调度任务 task, 等待任务回调
  3. 执行任务回调(render): 在内存中构造出 fiber 树, 同时与渲染器(react-dom)交互, 在内存中创建出与 fiber 对应的 DOM 节点.
  4. 输出(commit): 与渲染器(react-dom)交互, 渲染 DOM 节点

以上阶段的功能源码顺序是:

  1. 输入:只要涉及到需要改变 fiber 的操作(无论是首次渲染还是后续更新),最后都会间接调用scheduleUpdateOnFiber
  2. 注册调度任务:ensureRootIsScheduled
  3. 执行任务回调:performSyncWorkOnRootperformConcurrentWorkOnRoot
  4. 输出:commitRoot

哪些方法可以触发更新

只要涉及到更新操作,都会间接调用 scheduleUpdateOnFiber 函数。主动发起更新主要有三种方式:

  • class 组件中调用setState
  • function 组件中调用 hook 对象暴露处的dispatchAction
  • root节点上重复调用 render,官方示例

如何注册调度任务

  • performSyncWorkOnRoot 通过scheduleSyncCallback注册同步任务,逻辑是往全局的 syncQueue 队列中插入回调函数 callback,最后通过flushSyncCallbacks同步调用
  • performConcurrentWorkOnRoot 通过scheduler封装的scheduleCallback来注册异步任务。

render 阶段的源码流程

performSyncWorkOnRoot 构建 fiber 树的源码流程如下

  1. renderRootSync
  2. workLoopSync
  3. performUnitOfWork
  4. beginWork
  5. completeUnitOfWork

performConcurrentWorkOnRoot 构建 fiber 树的源码流程如下

  1. 需要时间切片进入renderRootConcurrent,不需要则进入 renderRootSync
  2. renderRootConcurrent 进入workLoopConcurrent,renderRootSync 进入 workLoopSync
  3. performUnitOfWork
  4. beginWork
  5. completeUnitOfWork

详细说下 render 阶段

render 阶段的构建过程分为以下两个阶段:

  1. 深度优先向下的 beginWork 探寻阶段:若节点有更新则计算新状态和 diff 之后生成新的 fiber 节点,然后在新的 fiber 节点打上 effectTag,最后 return 它的子节点,若子节点为空(也就是叶子节点)则进入 completeWork 回溯阶段
  2. completeWork 回溯阶段:根据 beginWork 阶段创建的 fiber 节点创建(或更新)其 DOM 对象,并且自下而上收集 effectList,最终收集到 root 上

在 Concurrent 模式下,render 阶段可被打断

可中断更新的实现原理

详细说下 commit 阶段

commit 阶段主要处理的是副作用队列,分为 以下三个阶段:

  1. commitBeforeMutationEffects:DOM 变更前,处理副作用队列中带有 Snapshot,Passive 标记的 fiber 节点
  2. commitMutationEffects:DOM 变更,界面得到更新. 处理副作用队列中带有 Placement, Update, Deletion, Hydrating 标记的 fiber 节点
  3. commitLayoutEffects:DOM 变更后,处理副作用队列中带有 Update | Callback 标记的 fiber 节点

渲染器 react-dom

  • 引导 react 应用的启动(通过 ReactDOM.render)
  • 实现 HostConfig 协议(源码在 ReactDOMHostConfig.js 中), 能够将 react-reconciler 包构造出来的 fiber 树表现出来, 生成 dom 节点(浏览器中), 生成字符串(ssr)

参考

Published under  on .

pipihua

我是皮皮花,一个前后端通吃的前端攻城狮,如果感觉不错欢迎点击小心心♥(ˆ◡ˆԅ) star on GitHub!