React16:Fiber架构学习总结

您好,我是沧沧凉凉,是一名前端开发者,目前在掘金知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。


最近疯狂的在看一些React原理上的知识,学去学来发现Fiber架构在整个React原理中占据了非常大的作用,比如说react-hooks的原理,context的原理,这些都需要Fiber理论知识进行支撑,还包括JSX的渲染,如何手动实现React.createElement方法,这些都需要了解Fiber。

所以我暂时抛弃了上面一系列知识点的学习,专门来学习一下Fiber。

前言

虽然本篇文章不从盘古开天辟地说起,但是也得说说为什么React团队在React16的时候将整个React框架重构,因为只有知道了原因,你才能更好的理解Fiber结构的设计思想。

浏览器刷新

主流浏览器刷新频率为60Hz,经常玩游戏的朋友肯定清楚,当FPS等于或者高于60FPS的时候,画面表现就会很流畅,而当低于60FPS的时候,画面就会出现一顿一顿的情况,如果低于30FPS,那游戏画面就会出现明显的卡顿,如果这个数值为个位数或者十位数,那么就是我们经常说的:卡成PPT了。

浏览器也是一样的如果要达到每秒60帧,那么浏览器的画面必须每(1000ms / 60Hz)即16.6ms刷新一次,如果超过了这个时间,那么网页界面可能会出现卡顿的情况,所以浏览器在16.6ms内,必须完成下面的三个步骤:

JS脚本执行 -----  样式布局 ----- 样式绘制

如果JS脚本执行时间超过16.6ms那么这一帧内就没有时间供浏览器进行样式布局、样式绘制了,也就是说这一帧内,浏览器的画面就不会进行刷新,必须要等到JS脚本执行完毕后,浏览器的界面才会进行更新。

打个比方就像你看一部电影,看着看着因为网络不好而获取不到电影的数据,那么画面就会卡在那里,等待数据获取完毕后才会正常播放,那么各大视频网站是怎么解决这个问题的呢?肯定不是点开电影的时候直接将整部电影进行缓存,它们会分段,将电影所需要的资源传递过来,即先加载一小部分,保证你能正常播放的情况下,再偷偷的从后台一段段的获取剩下的部分。

虽然上面的例子可能不太准确,但我自己感觉挺形象的。

React就是为了实现在浏览器每一帧的时间中,预留一些时间给JS线程,React利用这部分时间更新组件,而当JS的执行时长大于预留时间的时候,React就会将控制权交还给浏览器,让浏览器有足够的时间渲染UI,React就等待下一帧的预留时间来继续被中段的工作。

那么以前的React架构不能实现这个需求嘛?React团队就非得将整个框架进行重构才能完成这个需求?

答案是:不能。因为React15欠缺了一个角色。

欠缺了一个分配任务的角色(Scheduler),如果要分段执行JS脚本,那么肯定得有一个角色来负责脚本调度的优先级,先干什么,后干什么,而且在React15中没有双缓存机制,正是由于角色和机制的欠缺,导致React团队必须得重构React,而本次重构新增加的一系列东西,就叫做Fiber。

Fiber

Fiber的中文翻译叫做纤程,其实Fiber和JS中的Generator非常的相似,都是可以中断与恢复,并且恢复后可以复用之前的中间状态。

那么既然JS中已经有了Generator,为什么React团队还要去实现Fiber呢?

因为Generator虽然可以实现中断与恢复的功能,但是它很难实现任务的优先级,上面提到了Scheduler(调度器),它是负责调度任务的优先级。

虚拟DOM

在React16之后,虚拟DOM在React中有了一个正式的名称,就叫做Fiber。因为React中的所有虚拟DOM,在源码中最终都会被转换成FiberNode对象,而根节点则是FiberRootNode对象,现在请记住这FiberRootNodeFiberNode这两个对象名称,后面提到Fiber工作原理的时候会经常出现。

之前的React架构

之前的架构分为两层:

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

没错,上面提到的Scheduler(调度器)在之前的架构中是不存在的,为什么React在之前的架构中要分Reconciler和Renderer两个角色呢?

Reconciler

可能你听过React Native,它是专门用来混合开发安卓和IOS的APP应用,而浏览器上的DOM渲染和React Native上的渲染器区别很大,而为了让声明式渲染,自定义组件,state,生命周期方法和 refs 等特性,保持跨平台工作一致,所以React提取出了这部分方法,单独称他为Reconciler(协调器)。

在之前的架构中,React称呼它为stack reconciler。

Renderer

因为React支持跨平台,所以不同平台有不同平台的Renderer,而我们主要需要关注:ReactDOM

缺点

正如前文所说,这个时期的stack reconciler会递归更新子组件,无法实现中断更新、恢复更新,并且保留中间状态。

所以React官方将stack reconciler完全进行了重构,这就带来了下面的Fiber架构。

Fiber架构

在Fiber架构中,分为三层:

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

Scheduler

Fiber架构中新增的角色,主要是判断浏览器是否有剩余时间,起到中断任务的作用,在后面的总结文章中,Scheduler是一个重点,React专门讲它发布成了一个npm包:scheduler

Reconciler

其中Reconciler被React团队完全重写了,React称呼它为“fiber” reconciler。

重写后它的主要目标是:

  • 能够把可中断的任务切片处理。
  • 能够调整优先级,重置并复用任务。
  • 能够在父元素与子元素之间交错处理,以支持 React 中的布局。
  • 能够在 render() 中返回多个元素。
  • 更好地支持错误边界。

这个也是我后面会重点梳理的知识,所以现在就不进行过于深入的探讨。

Fiber节点

  1. 作为静态的数据结构来说,每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息。
  2. 作为动态的工作单元来说,每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…)。

最后

当你清楚了本文所述的内容时,你的心中大概就有一个印象,其实Fiber架构的出现是为了实现快速响应的理念。

其实在我的学习过程中,有一大堆的新概念非常打消我的学习积极性,所以本文中省略了非常多的在现阶段难以理解的概念。

所以我非常推荐各位看一下React技术揭秘-React理念章节


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!