react

0
open
sqshada
sqshada
Posted 1 month ago

react #11

React 15

架构分层

  • reconciler(协调器);负责找出变化大组件
  • renderer(渲染器);负责将组件的变化渲染到页面上

Reconciler

React 可以通过 setStateforceUpdateReactDOM.render 来触发更新,每当有更新发生时 Reconciler 会做如下工作:

  • 调用组件的 render 方法,将返回的 JSX 转化为虚拟 DOM
  • 将虚拟 DOM 和上一次的虚拟 DOM 对比
  • 通过对比找出本次更新中变化的虚拟 DOM
  • 通知 Renderer 将变化的虚拟 DOM 渲染到页面上

Renderer

在对某个更新节点执行完 Reconciler 后,通知 Renderer 进行节点渲染/更新

缺陷

React 15 的 diff 过程是递归执行更新,一旦开始便无法中断,当层级太深或者 diff 逻辑太复杂,就会造成线程卡住

React 16

架构分层

  • Scheduler(调度器);调度任务到优先级,高优任务优先进入 Reconciler
  • Reconciler(协调器);负责找出变化大组件
  • Renderer(渲染器);负责将组件的变化渲染到页面上

Scheduler

采用的是 合作式调度,即主动中断和控制器出让。判断标准为超时检测。
同时借鉴了 requestIdleCallback 接口,当浏览器有时间时执行通知。
除了在空闲时触发回调的功能外,Scheduler还提供了多种调度优先级供任务设置。

为什么不直接用 requestIdleCallbackrequestIdleCallback 工作只有 20FPS,一般对用户来感觉来说,需要到 60FPS 才是流畅的, 即一帧时间为 16.7 ms,所以这也是 react 团队自己实现 requestIdleCallback 的原因。

Reconciler

React 16 使用了一种新的数据结构 Fiber,Virtual DOM 树由之前的树形结构变化成了基于多向链表的图。
在React 16中,Reconciler 与 Renderer 不再是交替工作。当 Scheduler 将任务交给 Reconciler 后,Reconciler 只是会为变化的 Virtual DOM 打上代表增/删/更新的标记,而不会发生通知 Renderer 去渲染。

只有当所有组件都完成Reconciler的工作,才会统一交给Renderer进行渲染更新。

Renderer

Renderer 根据 Reconciler 为 Virtual DOM 打的标记,同步执行对应的渲染操作。

流程为:

  1. setState 等产生更新
  2. 更新交给 Scheduler,Scheduler 发现没有其他高优先级任务,将该任务交给 Reconciler
  3. Reconciler 接到任务后,开始遍历 Virtual DOM,判断哪些需要更新,打上标记
  4. Reconciler 遍历完所有的 Virtual DOM,通知 Renderer
  5. Renderer 根据 Virtual DOM 标记执行对应的节点操作

其中 2、3、4 随时可能被中断:

  • 有其他高优先级任务需要更新
  • 当前帧没有剩余时间

源码分析