React 源码分析 (一)Fiber
前言
本次 React 源码参考版本为17.0.3
。
React 架构前世今生
查阅文档了解到, React@16.x
是个分水岭。
React@15 及之前
在 16 之前,React 架构大致可以分为两层:
Reconciler: 主要职责是对比查找更新前后的变化的组件;
Renderer: 主要职责是基于变化渲染页面;
但是 React 团队意识到这样的架构有致命问题: 因为在 React15 中,组件的更新是基于递归查找实现的,这样一旦开始递归,是没有办法中断的,如果组件层级很深,就会出现性能问题,导致页面卡顿。
React@16 及之后
为了解决这样的问题,React 团队在React@16
进行了重构,引入了新的架构模型:
Reconciler: 主要职责是对比查找更新前后的变化的组件;
Renderer: 主要职责是基于变化渲染页面;
Scheduler: 主要职责是区分任务优先级,优先执行高优先级的任务;
新的架构在原来的基础上引入了Scheduler(调度器)
,这个东西是 React 团队参考浏览器的 API:requestIdleCallback
实现的。它的主要作用就是调度更新任务:
一方面可以中断当前任务执行更高优先级的任务;
另一方面能判断浏览器空闲时间,在恰当的时间将主动权给到浏览器,保证页面性能;并在浏览器下次空闲时继续之前中断的任务; 这样就将之前的不可中断的同步更新变成了异步可中断更新,不直接使用浏览器 API 可能考虑到兼容问题,可能也有别的方面的考量。下面是新的 React 架构更新模型:
这个新的架构在进入 Renderer 之前的流程是可以被中断的,主要有下列两种情况:
进入了更高优先级的任务;
浏览器在当前帧没有剩余空闲时间了;
Fiber
Fiber 简单的理解就是React15
版本的虚拟 DOM。
Fiber 简单理解
如果将新的 React 架构比作一个公司,Fiber 在新的架构里承担的就是这个公司的员工,员工也有等级,老板,部长,基层,每个人有自己的职责,知道自己在哪个节点该做什么工作,并将未完成的工作记住等第二天上班继续完成,从而保证公司的顺利运行。而每个 Fiber 对应一个React element
:假如有这样一段代码:
上面的代码的抽象 Fiber 树:
其中的每个方块都是一个 Fiber,它们通过child, return, sibling
连接对方构成一个 Fiber 树。相关参考视频讲解:进入学习
Fiber 结构
来看一个 Fiber 会有哪些属性:
Fiber 工作原理
在弄明白 Fiber 工作原理之前,我们要先明确一个认知:新的 React 架构使用了两个 Fiber 树。
一个 Fiber 树是当前页面 dom 的抽象,叫
current
;另一个 Fiber 树是在内存中执行更新任务 dom 的抽象,叫
workInProgress
;
这样做是为了方便比对变化组件,并降低创建的成本,尽可能复用现有代码逻辑,从而提高渲染效率。
mount
React 代码在第一次执行时,因为页面还没有渲染出来,此时是没有current
树的,只有一个正在构建 DOM 的workInProgress
树。
假如我们有这样一段代码:
基于上面的代码在mount
会生成这样的 Fiber 树:
可以看到这个图只是在前面的图上增加了fiberRoot
和rootFiber
两个 Fiber 节点。
fiberRoot:整个 React 应用的根节点;
rootFiber: 某个组件树的根节点;(因为我们可能多次使用
React.render()
函数,这样就会有多个 rootFiber)
图中此时 fiberRoot 对应的 rootFiber 下面还是空的,因为此时是第一次渲染,页面上没有任何东西,当workInProgress
树构建完成,在mutation
之后,layout
之前,fiberRootd 的current
指针会指向workInProgress
树,把它作为新的current
树,此时结构会变成这样:
这时页面渲染完成了,等待下次触发更新时会从current
树进行拷贝生成workInProgress
树,然后比对更新。
update
如果我们在上面的代码中触发更新,将牛牛
文本改成了勇敢牛牛
,React 代码就会开始进行任务调度,因为只有这一个任务,会马上执行,会从current
树的 rootFiber 进行拷贝生成workInProgress
树的根节点,在经过向下遍历比对,发现相同的就直接从current
树上拷贝复用,直到比对到叶子节点的牛牛
文本变了,这时才会生成新的 Fiber(这里只是为了方便解释,其实我这里使用的代码牛牛
不会生成新的 Fiber,因为是纯文本,只会替换父级节点的 props)
评论