当前位置: 首页 > Web前端 > HTML

浅谈Fiber架构的工作流程

时间:2023-03-28 11:01:09 HTML

Fiber起源Fiber架构诞生于React16,解决了React15及之前版本更新无法中断的问题。StackCoordinatorStackReconciler我们知道React在工作的时候有一个重要的阶段叫做协调阶段Reconcile。在React15中,React仍然使用堆栈协调StackReconciler。之所以叫栈协调,是因为React是使用递归构建虚拟Dom树(React15的名称),在构建过程中,数据保存在递归调用栈中。由于递归是同步执行的,所以只能执行一次,不能中途中断。这样一来,当浏览器执行代码时,StackReconciler由于需要协调很多节点,往往会耗费大量时间,导致浏览器的UI渲染工作延迟,从而导致浏览器掉帧肉眼。FiberCoordinatorFiberReconciler为了解决StackReconciler的递归调用,React团队在React16发布时推出了全新的Fiber架构,旨在解决老版本不间断更新的问题。React团队提出了一种新的模式**ConcurrentMode**。一个大的同步任务可以分解成很多个小的同步任务。当浏览器运行时,这些小的同步任务被均匀地塞进每一帧中。在一小段时间内执行,我们称之为可中断的异步更新。而我们知道,在React15中,由于架构的限制,同步任务是离不开的。一旦任务被挂起,所有的任务只能被打断。但是权限的fiber架构可以保存更新的运行状态,这样下次调用的时候可以继续上次的更新。因此,Fiber架构为ConcurrentMode的实现奠定了基础。这种可中断更新解决了卡顿和掉帧的问题,也给用户带来了更好的交互体验。Fiberworkflow在React15中,我们知道有一个虚拟的DOM树,用来和真实的DOM建立映射关系。在Fiber架构中,我们将物种映射到Fiber树中。一个Fiber由一个当前应用根节点FiberRootNode和一个当前组件树根节点rootFiber组成。rootFiber实际上是一个FiberNode,它连接到一个由其他FiberNode组成的子树。FiberRootNode通过当前指针连接到当前组件树的rootFiber。这里我们用currentcomponenttree这个词,其实就是介绍Fiber架构下的双缓冲机制。双缓冲机制我们在处理图像的时候,经常会经历渲染屏幕-清屏-重新渲染屏幕的过程。清除屏幕后重新绘制屏幕可能很耗时。这时候,用户就会感知到闪屏现象。如果我们在内存中构建当前帧,构建完成后直接替换上一帧,省去了清屏,这样可以节省大量时间,大大提升用户体验。所以在React中,我们也采用了双缓冲机制,即系统中始终存在两棵Fiber树,其中一根对应当前显示在屏幕上的DOM,称为current。这个时候,我们称它为当前的组件树,在内存中建立了一个新的Fiber树,叫做workInProgress,我们这个时候称它为正在构建的组件树。Fiber树示例在以下代码渲染的组件中/header>

);}一个完整的Fiber树示例如图:根节点FiberRootNode会使用current指向当前组件树,当前组件树的根节点rootFIber会使用child指向子节点。如果有多个子节点节点,那么子节点将使用兄弟指针连接。Fiber首屏渲染下面换个简单的例子来更好的理解渲染过程:functionApp(){const[num,setNum]=useState(0);return(setNum(num+1)}>{num}

);}一开始React会先建立FiberRootNode和rootFiber作为初始的Fiber树。FiberRootNode当前指针指向rootFiber,此时rootFiber为空。然后根据组件树返回的jsx对象(即createElement的返回值对象)在render阶段新建一个rootFiber。这一步是递归创建workInProgress。创建workInProgress后,然后在提交阶段将树渲染到页面。这时修改current指针指向workInProgress,使其成为新的currenttree。这是Fiber的首屏渲染流程。current和workInProgress是通过alternate连接的,后面会讲为什么要这样做。Fiber树更新当我们点击p触发页面更新后,React会在内存中重建一个完整的Fiber树,即workInProgress。构建完成后,会直接让current指针指向它,然后render阶段会根据这个新的current来渲染。在这个过程中,我们可以通过Diff算法来决定是否复用当前树中的节点,这样就省去了创建节点的过程,进一步加快了渲染过程。节点复用我们之前说过,当页面更新时,由于React的双缓冲机制,在渲染页面时,会先从内存中构建一个Fiber树,构建完成后,直接改变指向当前指针替换Drop当前Fiber树,达到页面更新的目的。所以在构建workInProgress树时,我们实际上还有一个当前树。由于大部分的更新只是某种风格的改变或者小规模的数据更新,所以UI的变化不是很大。如果此时我们还在内存中从头渲染一棵完整的Fiber树是比较耗时的,那么我们可以复用一些节点,根据当前树创建一个workInProgress树,我们会用到Diff算法(有兴趣的朋友可以自己学习)来决定是否重用该节点,要重用的节点为current.alternate。现在可能有朋友会问了,current.alternate不是一棵完整的树吗,怎么直接复用呢?其实在构建workInProgress的时候,current是不断变化的,它是和workInProgress同步移动的。