react强制刷新页面_React架构知其然

v2-8a6ebc813b3fbab548f06b3c3f7eb49a_1440w.jpg?source=172ae18b

React 15架构

架构分为两层:

  • Reconciler(调和器):负责找出变化的组件
  • Renderer(渲染器):负责将变化的组件渲染到页面上


渲染流程:

v2-0ed360af3cf3642ddda6acb9a3849679_b.png


Reconciler(调和器)


React 15中又称为 Stack Reconciler。
this.setStatethis.forceUpdateReactDOM.render等API触发状态更新后,Reconciler会递归连续不可中断得完成如下工作:

  1. 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  2. 将虚拟DOM和上次更新时的虚拟DOM进行同步递归对比(React Diff算法)
  3. 通过对比找出本次更新中变化的虚拟DOM
  4. 通知Renderer将变化的虚拟DOM渲染到页面上

递归过程中的连续不可中断容易导致用户交互出现卡顿,这里简单做下分析。
回顾下浏览器渲染工作原理:

浏览器刷新频率为60Hz,即每16.6ms(1000ms / 60Hz)浏览器刷新一次。
由于GUI渲染线程与JS线程是互斥的,所以JS脚本执行和浏览器布局、绘制不能同时执行。
即在每16.6ms时间内,需要完成如下工作: JS脚本执行 -----> 样式布局 -----> 样式绘制
JS脚本执行消耗时长超出16.6ms时,该次刷新就无法完成 样式布局样式绘制

从中可看出,倘若Reconciler的工作内容非常耗时,即JS脚本执行阶段耗时超出16.6ms时,会阻塞整个线程。
Stack Reconciler的主要缺陷也十分明显:

  • 无法暂停渲染任务
  • 无法切分任务
  • 无法有效平衡组件更新渲染与动画相关任务间的执行顺序。即不能划分任务优先级,有可能导致重要任务卡顿,动画掉帧等问题。


Renderer(渲染器)


React支持跨平台,不同平台有不同的Renderer(渲染器)。

  • ReactDOM渲染器:渲染浏览器DOM
  • ReactNative渲染器:渲染App原生组件
  • ReactTest渲染器:渲染出纯Js对象用于测试
  • ReactArt渲染器:渲染到Canvas, SVG 或 VML (IE8)

在每次更新发生时,Renderer接到Reconciler通知,将变化的组件渲染在当前宿主环境。


React 16架构


架构分为三层:

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


渲染流程:

v2-47d5aa9316e938584101f581be670868_b.png


Scheduler


上一节已知,每16.6ms浏览器刷新一次,即为一帧。浏览器线程执行任务时会以帧的形式划分,在两个执行帧之间,主线程通常会有一小段空闲时间,称为空闲期(Idle Period)。
目前主流浏览器提供了 requestIdleCallback API,支持在空闲期内调用空闲期回调(Idle Callback),执行一些任务。与之相对的,高优先级任务由requestAnimationFrame API执行,如动画等。
利用任务优先级高低,分别调度执行函数,可解决React 15的交互卡顿问题。
React 16 基于这个原理实现了功能更完备的requestIdleCallback polyfill,也就是Scheduler


Reconciler


React 16 的Reconciler,又被称为 Fiber Reconciler。
Fiber Reconciler 通过引入新的数据结构——Fiber对象,配合Scheduler解决了Stack Reconciler的缺陷。即渲染进程可分段完成,而不必一次性完成,期间优先执行其他高优先级任务。
观察源码可以发现,更新工作从递归变成了可以中断的循环过程。每次循环都会调用shouldYield判断当前是否有剩余时间。

/** @noinline */ 
function workLoopConcurrent() {  
  // Perform work until Scheduler asks us to yield
  while (workInProgress !== null && !shouldYield()) {
  performUnitOfWork(workInProgress);
} }

那么,Fiber对象如何实现渲染进程可分段完成呢?

  1. 首先,DOM组件实例均对应一个fiber实例,fiber实例负责管理组件实例的更新,渲染任务及与其他fiber实例的联系。
  2. 其次,fiber的工作是在内存中进行的,工作的结果交由 Render处理。

由于是在内存中加工处理fiber实例,本质是对数据的处理,其工作也就可以被暂停,且支持优先级调度。
在对数据的处理过程中,Reconciler会为需要变化的虚拟DOM打上代表增/删/更新的标记。

// You can change the rest (and add more). 
export const Placement = /*                    */ 0b000000000000010; 
export const Update = /*                       */ 0b000000000000100; 
export const PlacementAndUpdate = /*           */ 0b000000000000110; 
export const Deletion = /*                     */ 0b000000000001000; 
export const ContentReset = /*                 */ 0b000000000010000; 
export const Callback = /*                     */ 0b000000000100000; 
export const DidCapture = /*                   */ 0b000000001000000; 
export const Ref = /*                          */ 0b000000010000000; 
export const Snapshot = /*                     */ 0b000000100000000; 
export const Passive = /*                      */ 0b000001000000000; 
export const PassiveUnmountPendingDev = /*     */ 0b010000000000000; 
export const Hydrating = /*                    */ 0b000010000000000; 
export const HydratingAndUpdate = /*           */ 0b000010000000100;


Render

Renderer与React 15 的Renderer类似。不同的是,根据Reconciler为虚拟DOM打的标记,同步执行对应的DOM操作。
DOM的操作主要分为:

  • 插入DOM节点(Placement)
  • 更新DOM节点(Update)
  • 删除DOM节点(Deletion)


视觉差异


从实际视觉Demo中可以明显看出Stack ReconcilerFiber Reconciler 的差异性。

此处引用 https:// github.com/claudiopro/r eact-fiber-vs-stack-demo


React15中,由于大量的同步计算任务阻塞了浏览器的 UI 渲染,造成页面卡顿。

v2-9af4c676d8771189740c052dac66c489_b.gif


相比之下,React16的效果非常流畅。但由于Facebook比较慎重,在16的前期版本中默认没有启用该功能,但可以在Dev环境下手动开启。

v2-706ceaa233acb9d0d3b713ccf7948da7_b.gif


参考

  • https://react.iamkasong.com/
  • https://github.com/claudiopro/react-fiber-vs-stack-demo

如果觉得文章能帮助你理解一些前端知识点,请关注微信公众号。

v2-050b20a1d51e9168e7b2631ca3957a69_b.jpg
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值