react 虚拟DOM的diff算法

文章目录

      • 浅谈传统 diff和React diff(16之前的diff)
        • 类型比较
        • 针对组件元素的比较
        • 对子节点进行递归
        • key
        • React中应该如何去配合diff算法提高性能?
      • 三大策略
        • tree diff
        • component diff
        • element diff
      • 小结

今天对diff算法(React16之前)进行了一些学习。

浅谈传统 diff和React diff(16之前的diff)

关于树转换成另一颗树的最小操作数这个问题,最前沿的算法(循环递归比较节点是否相同)的时间复杂度是O(n3)。即对两颗树的节点进行时间复杂度为O(n2)的两两比较,比较结束之后,计算节点到节点的编辑距离(类似海明距离的概念,对节点进行增加、删除、修改等等),这一步需要O(n)的时间,所以最后是O(n3)。

传统diff最大的劣势就是太慢了,尽管它能够适应所有形状的树。React基于两种假设,提出了一套O(n)的启发式算法:

假设一:两种不同类型(type)的元素会产生不同的树;

假设二:开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定。

类型比较

React中针对假设一的策略,就是对不同的根节点进行比较,假如类型不同(比如说div变成了span),就进行拆卸,对整颗树进行重建。例如:

<div>
  <Counter />
div>

<span>
  <Counter />
span>

Counter或许是同一个Counter,但因为根节点的不同,会被销毁并重新mount一个新的。

那么类型相同又何如?针对两个相同类型的React元素,原先的DOM节点将被保留,仅对比和更新发生了改变的属性:

<div className="before" title="stuff" />

<div className="after" title="stuff" />

style同理,只更新有变化的属性(下面的color):

<div style={
    {color: 'red', fontWeight: 'bold'}} />

<div style={
    {color: 'green', fontWeight: 'bold'}} />

处理完当前节点,就继续递归子节点。

针对组件元素的比较

组件更新时,实例将保持不变,进而state数据也会保持一致,会更新的是组件实例的props,触发调用组件元素实例的componentWillReceiveProps()componentWillUpdate() 方法(比如说用redux传递props的时候,组件中仅props发生了更新,这时需要依赖着两个生命周期函数去监听组件发生了什么变化)。

接下来,调用render()方法,diff算法开始比较。

对子节点进行递归

在默认条件下,当递归 DOM 节点的子元素时,React 会同时遍历两个子元素的列表;当产生差异时,生成一个 mutation。比如说下面的例子,列表尾部新增一个元素,只会有一个mutation,更新开销很小:

<ul

你可能感兴趣的:(React学习记录)