前提:本文假使浏览器的刷新率都是16ms。
stack
在React在使用Fiber架构之前,它使用的是一种称为Stack架构来处理组件的更新和DOM渲染。Stack架构的核心是一种递归算法,叫做Stack Reconciliation。通过递归地遍历组件树来确定需要更新的部分,并进行相应的DOM操作。
Stack Reconciliation的工作原理
在Stack Reconciliation算法中,当组件的状态发生变化时,React会从根组件开始递归地遍历整个组件树,对比新旧组件的状态,找出需要更新的部分,并进行更新。
具体步骤如下:
- Diffing(对比):React会逐层比较新旧组件树的节点,找出有变化的部分。
- 更新:根据对比的结果,React会执行相应的DOM操作,包括更新、插入和删除节点,以确保UI与最新的状态保持一致。
Stack Reconciliation的特点: - 递归遍历:Stack Reconciliation算法是通过递归遍历组件树来进行更新的,这意味着在处理大型组件树时可能会导致性能问题。
- 同步更新:更新是同步进行的,即在一次JavaScript执行周期内完成整个更新过程。
- 阻塞渲染:由于更新是同步的,可能会导致UI线程阻塞,影响用户体验。
缺点
因为stack架构在对比UI变化时,会采用递归遍历整棵组件树,如果组件树体积过大,计算的时间过长,就可能导致浏览器丢帧。
在60Hz的显示器上,浏览器每16ms更新一帧,如果js代码的计算时间超过16ms,就会让浏览器“错失”这个更新页面的机会,导致界面丢帧。
Fiber
为了提升React构建快速响应的大型 Web 应用程序的能力,在16版本中,React将stack架构更换为威名赫赫的———Fiber。都说Fiber牛,那么具体牛在哪呢??
1. 采用多重链表记录Dom元素
想象你正在玩一个拼图游戏,每个拼图块都代表一个组件,而游戏的目标是将这些拼图块按照正确的顺序拼接在一起,形成完整的图片(即页面渲染)。现在让我们用两种不同的方法来玩这个游戏,一种是使用Stack(堆栈)的方式,另一种是使用Fiber的多重链表方式。
- Stack(堆栈)方式: 在Stack方式下,你必须按照固定的顺序依次拼接每个拼图块,只有当上一个拼图块拼接完成后,才能继续拼接下一个拼图块。
- Fiber的多重链表方式: 在Fiber的多重链表方式下,你可以灵活地选择拼接哪个拼图块,而不需要按照固定的顺序。每个拼图块都有指示下一个拼图块的指针,你可以根据自己的需要选择拼接的顺序。
2. 时间分片
Fiber 架构将大的渲染任务分割为更小的单元,这些小单元可以在多帧之间分配执行。这意味着浏览器主线程有更多的机会在渲染任务之间处理布局和绘制任务,从而避免长时间阻塞。即:把单个js任务的时间控制在16ms以内,防止浏览器ui线程的阻塞从而丢帧。
还是继续想象你在玩拼图,stack和fiber的区别在于:
- 在Stack方式下,即使某个拼图块比较复杂,可能需要花费很长时间来完成,你仍然需要一口气完成整个拼图过程,否则无法正确完成拼图。
- 在Fiber方式下,你可以随时暂停、切换或调整拼图的顺序。这样即使某个拼图块比较复杂,你也可以暂时放下并继续拼接其他简单的拼图块,然后再回来继续复杂的部分,保持游戏的流畅性和灵活性。
3. 优先级调度
因为Fiber架构允许你在拼图的时候随心所欲,根据自己的喜好来优先拼出拼图的某一部分,体现到代码层面就是Fiber架构可以根据任务的优先级来调度执行顺序,高优先级的任务(如用户输入响应、动画等)可以优先得到处理,这样可以增加用户的操作体验——即你拼拼图的游戏体验。
这一功能的实现,得益于v16中新增的调度器——Scheduler。Scheduler可以调度任务的优先级,高优先级的任务会优先执行。除此之外,Scheduler还支持任务的中断和恢复功能,即可以中断当前正在执行的任务,并在恢复时继续执行,这样也可以避免UI线程的阻塞。
最后,再放一个Stack和Fiber的对比链接:claudiopro.github.io/react-fiber…