一、React架构演变历程
1、React15以及之前的架构属于Stack架构
2、React16版本开始,React重构了整体的架构,新的架构是Fiber架构
3、新的架构相对于之前的架构,最大的特点就是能够实现时间切片
二、旧的架构有哪些问题
众所周知,包括在官网中也有描述,React是用javascript构建的快速响应的大型web应用程序
但是在实际应用中,会存在一些因素影响快速响应的,比如:
1、当你进行大量计算的时候或者设备本身性能不足的时候,页面会出现卡顿、掉帧的现象,这个本质就是CPU的瓶颈
实际上,我们所看到的网页,其实是一帧一帧的绘制出来的,浏览器的刷新频率是60赫兹,每秒要绘制60次,也就是浏览器每隔16.66毫秒就要绘制一帧,正常一帧会执行以下操作
HTML解析、样式计算、布局、分层、绘制、分块、光栅化、画
其中,HTML解析、样式计算、布局、分层、绘制在渲染线程
分块、光栅化、画在合成线程
当然也并不是所有任务都经过以上步骤
- 当js或者样式修改dom的几何大小属性的时候,以上流程都会触发,这种叫做重排
- 当不涉及几何属性的时候(颜色等),会省略掉绘制、分层过程,这种叫做重绘
- 当涉及transfrom属性的时候,会只执行合成线程的过程(分块、光栅化、画)
在浏览器的渲染原理我们知道,js的执行和页面的渲染都在渲染主线程中,如果js的执行时间过长,就不能够及时渲染下一帧,会导致掉帧,实际看上去就会卡顿
在React16之前就会存在这个问题,当页面层级很复杂的时候,js代码执行的时间过长。在React中,需要计算整颗虚拟dom树,虽然说是js层面的计算,相比直接操作dom,节省了很多时间,但是每次重新去计算整颗虚拟dom树,会造成每一帧的js代码执行时间过长,从而导致动画、一些实时更新得不到及时得响应,就会造成卡顿得视觉效果
在React16之前,进行两颗虚拟dom树得对比,需要遍历涉及上面树得结构,这个时候就要用到递归,而且这种递归是不能够打断得,从而造成了js执行时间过长
这样的架构就是Stack架构,因为采用的是递归,不停的开启新的函数调用栈
2、进行I/O的时候,需要等待数据返回后再进行后续操作,等待的过程中无法快速响应,这个本质就是I/O的瓶颈
对于我们前端来说,最主要的I/O瓶颈就是网络的 延迟。
网络延迟是一种客观存在的现象,那么我们如何减少这种现象对用户的影响呢?React团队给出的答案就是将人机交互的研究成果整合到UI中。
在我们实际工作中,我们会发现,在进入一个首页时候,如果我们加个loading效果,哪怕过个几秒,其实用户也不会觉得卡;但是,如果页面有输入框,输入框哪怕只有轻微的延迟,用户也会觉得很卡;这就说明了,其实用户对于卡顿的感知是不一样的
对于React来说,UI=fn(state),所有的操作都是来自于自变量的变化导致的重新渲染,所以我们只需要针对不同的操作赋予不同的优先级即可。
具体来说:
- 为不同操作造成的自变量变化赋予不同的优先级
- 所有优先级统一调度,优先处理最高优先级的更新
- 如果更新正在进行,此时有更高优先级的更新产生的话,中断当前的更新,优先处理高优先级更新
要实现以上三点,那么需要React底层能实现
- 用于调度优先级的调度器
- 调度器对应的算法
- 支持可中断的虚拟dom的实现
所以基于以上,对于React来说,底层要实现时间切片,要分多个小任务单元
三、新的架构解决哪些问题
1、解决CPU的瓶颈
从React16之后,引入了Fiber的概念,这是一种通过链表来描述UI的方式,本质上就是一种虚拟dom的实现
Fiber 本质就是一个对象,但是和之前React元素不同就在于对象之间使用的是链表结构串联起来,child指向子元素,sibling指向兄弟元素,return指向父元素
使用链表结构,有一个最大的好处就是在进行整颗树的对比(reconcile)计算的时候,这个过程是可以被打断的
在发现一帧时间已经不够,不能够继续执行js,需要渲染下一帧的时候,这个时候就会打断js的执行,优先渲染下一帧。渲染完成后,再接着回来完成上一次没有执行完的js计算
2、解决I/O瓶颈
React16 之后引入了 Scheduler(调度器),用来调度任务的优先级
React16之前
- Reconciler(协调器):vdom的实现,根据自变量的变化计算出UI的变化
- Renderer(渲染器):负责将UI的变化渲染到宿主环境中去
React16之后
- Scheduler(调度器)调度任务的优先级,高优先级的任务会优先进入到Reconciler中去执行
- Reconciler(协调器)vdom的实现,根据自变量计算出UI的变化
- Renderer (渲染器)负责将UI的变化渲染到宿主环境中去
新的架构,Reconciler的更新流程也从之前的递归变成了 可中断的循环过程