React Fiber是React 16引入的一种新的协调算法和架构,它将渲染任务拆分为可中断、可恢复、带优先级的小单元,以提升应用响应性和用户体验。 React Fiber的出现背景与核心目标
-
解决Stack Reconciler的阻塞问题:在React 16之前,协调器(Reconciler)采用递归方式同步处理虚拟DOM的更新,一旦开始便无法中断。当组件树庞大时,长时间占用JavaScript主线程会导致浏览器无法及时响应用户交互或执行渲染,造成页面卡顿。
-
实现可中断与恢复的渲染:Fiber架构将整个渲染更新过程拆解为多个独立的小任务单元(称为Fiber节点),每个单元对应一个组件或DOM节点。React可以在执行完一个单元后,检查是否有更高优先级的任务(如用户输入)需要处理,从而暂停当前渲染,待空闲时再恢复执行,避免了长时间阻塞。
-
引入优先级调度机制:Fiber为不同类型的更新任务分配了优先级(如用户交互为高优先级,数据预加载为低优先级)。调度器(Scheduler)会根据优先级动态安排任务执行顺序,确保高优先级任务能立即得到响应,从而提升交互的流畅度。 Fiber架构的工作原理
-
任务分片与时间切片:Fiber将一次完整的渲染更新分解为多个可执行的Fiber节点处理单元。React利用浏览器的空闲时间(通过类似
requestIdleCallback的机制)分批执行这些单元,每执行一小段时间就检查是否还有空闲时间,从而将控制权交还给浏览器进行布局和绘制,实现流畅的"时间切片"效果。 -
链表数据结构:每个Fiber节点都是一个JavaScript对象,通过
child(指向第一个子节点)、sibling(指向下一个兄弟节点)和return(指向父节点)三个指针,构成一个链表式的树结构。这种结构使得遍历过程可以随时暂停和恢复,因为可以从当前节点快速找到下一个待处理的节点,而无需依赖递归调用栈。 -
双缓存机制:在内存中同时维护两棵Fiber树。当前树(current)对应屏幕上已渲染的内容,工作进展树(workInProgress)则是在后台构建的新树。更新发生时,React在workInProgress树上进行协调计算,完成后再一次性替换current树的指针。这种机制能够保证渲染的连续性,避免出现中间状态。
-
副作用与增量更新:在构建workInProgress树的过程中,React会对比新旧Fiber节点,并将需要执行的DOM更新(如增、删、改)标记为"副作用"。所有带有副作用的Fiber节点会被连接成一个链表(Effect List)。在最终的提交阶段,React会遍历这个Effect List,将所有变更一次性应用到真实DOM上,完成视图更新。 Fiber节点的数据结构与渲染流程
-
Fiber节点的核心属性:一个Fiber节点承载了组件的完整信息,主要字段包括:
- 标识信息:
tag(组件类型,如函数组件、类组件、宿主组件)、key、type(具体的组件函数或DOM标签)。 - 状态与属性:
memoizedState(组件上一次渲染后的状态)、memoizedProps(上一次渲染后的属性)、updateQueue(存储状态更新的队列)。 - 结构指针:
child、sibling、return,用于构建链表树。 - 副作用相关:
flags(标记节点需要进行的更新操作,如Placement、Update、Deletion)、subtreeFlags、nextEffect(用于构建Effect List)。 - 双缓存指针:
alternate,指向在另一棵树中对应的Fiber节点。
- 标识信息:
-
两大渲染阶段:
- 渲染/协调阶段(Render/Reconciliation Phase):此阶段可中断。React会深度优先遍历Fiber树,构建workInProgress树,并在此过程中完成组件的状态计算、Diff比较以及副作用的收集标记。
- 提交阶段(Commit Phase):此阶段不可中断,会同步执行。React将渲染阶段收集到的所有副作用(Effect List)应用到真实DOM上,并执行相应的生命周期函数(如
componentDidMount、componentDidUpdate)或Hook回调(如useLayoutEffect)。