Fiber Reconcile 与 Stack Reconcile 主要有两方面的不同。
首先,使用协作式多任务处理任务。将原来的整个 Virtual DOM 的更新任务拆分成一个个小的任务。每次做完一个小任务之后,放弃一下自己的执行将主线程空闲出来,看看有没有其他的任务。如果有的话,就暂停本次任务,执行其他的任务,如果没有的话,就继续下一个任务。
整个页面更新并重渲染过程分为两个阶段。
-
Reconcile 阶段。此阶段中,依序遍历组件,通过diff 算法,判断组件是否需要更新,给需要更新的组件加上tag。遍历完之后,将所有带有tag的组件加到一个数组中。这个阶段的任务可以被打断。
-
Commit 阶段。根据在 Reconcile 阶段生成的数组,遍历更新DOM,这个阶段需要一次性执行完。如果是在其他的渲染环境 – Native,硬件,就会更新对应的元素。
所以之前浏览器主线程执行更新任务的执行流程就变成了这样。
其次,对任务进行优先级划分。不是每来一个新任务,就要放弃现执行任务,转而执行新任务。与我们做事情一样,将任务划分优先级,只有当比现任务优先级高的任务来了,才需要放弃现任务的执行。比如说,屏幕外元素的渲染和更新任务的优先级应该小于响应用户输入任务。若现在进行屏幕外组件状态更新,用户又在输入,浏览器就应该先执行响应用户输入任务。浏览器主线程任务执行流程如下图所示。
DOM diff算法的核心思想
- 两个相同组件产生类似的DOM结构,不同的组件产生不同的DOM结构;
- 对于同一层次的一组子节点,它们可以通过唯一的id进行区分。
逐层进行节点比较
- 只会对同一层次的节点进行比较
对于不在同一层的节点的比较,即使它们完全一样,也会销毁并重新创建。
React只会对相同颜色方框内的DOM节点进行比较,即同一个父节点下的所有子节点。当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。这样只需要对树进行一次遍历,便能完成整个DOM树的比较。
相同类型节点的比较
React会对属性进行重设从而实现节点的转换。
列表节点的比较
如果给每个节点唯一的标识(key),那么React能够找到正确的位置去插入新的节点,