React 虚拟 Dom 和 diff 算法

React将DOM抽象为虚拟DOM, 然后通过新旧虚拟DOM 这两个对象的差异(Diff算法),最终只把变化的部分重新渲染,提高渲染效率的过程; (概念讲完再描述一遍)

JS对象2Html.png
JS对象2HTML完整版.png
虚拟DOM的算法步骤.png

一句话: 用 JS 对象的形式,来表现一棵真是的 DOM 树;


Diff 算法

    • 当你实际开发使用React的时候,在某个时间点 render() 函数创建了一棵React元素树,也就模拟一个虚拟 DOM 树,
    • 在下一个state或者props更新的时候,render() 函数将创建一棵新的React元素树, 也就模拟了一个新的虚拟 DOM 树,
    • 既然模拟出了新旧两棵DOM 树, 那么如何高效的进行新旧两棵树的对比呢??
    • 当然是使用 DIff 算法...
  1. 传统的 Diff 算法也是一直都有的;

    • 但是它的时间复杂度为O(n^3)
      意思是: 在React中更新10个元素则需要进行1000次的比较。(1000个===10亿)
  2. React 通过制定大胆的策略,将 O(n^3) 复杂度的问题转换成 O(n^1=n) 复杂度的问题。

      1. 两个不同类型的元素会产生不同的树 <MyTest /> 和 <MyComponent />
      1. 对于同一层级的一组子节点,它们可以通过唯一 key 进行区分
    • 基于以上两个前提策略,React 分别对 tree diff、component diff 以及 element diff 三种 diff 方法是 进行算法优化,
    • 下面介绍优化后的几种算法

Tree Diff

概念: 将新旧两颗虚拟 DOM 树,按照层级对应的关系,从头到尾的遍历一遍,,就能找到那些元素是需要更新的,这种方式: Tree Diff

Tree Diff 01.png
1 只会对相同颜色方框内(同级)的DOM节点进行比较,即同一父节点下的所有子节点
2 当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较
Tree Diff 02.png
  • 执行过程:create A -> create B -> create C -> delete A

Component Diff

不同组件之间的对比
概念: 在对比每一个层级的时候,会有自己的组件,这种组件的对比方式就叫: Component Diff ;

​ 这种对比方法其实比较的就是类型.↓↓↓

  • 如果类型相同,暂时不更新,
  • 如果类型不相同,就需要更新; ( 删除旧的组件,再创建一个新的组件,插入到删除组件的那个位置)
Component Diff 01.png
  • 执行过程:delete D -> create G

Element Diff

同一层级中元素之间的对比
概念: 在类型相同的组件内, 再继续对比组件内部的元素,查看内部元素是否相同,如果需要修改,找到需要修改的元素,进行针对性的修改! 这种方式就叫: Element Diff

三种节点操作:
1 INSERT_MARKUP(插入)
2 MOVE_EXISTING(移动)
3 REMOVE_NODE(删除)

INSERT_MARKUP:新的 component 类型不在老集合里,需要对新节点执行插入操作。

MOVE_EXISTING:老的集合包含新的 component 类型,就需要做移动操作,可以复用以前的 DOM 节点。

REMOVE_NODE:老的 component 不在新集合里的,需要执行删除操作 或者 老的 component 类型在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作
Element Diff 01.png
  • 执行过程:B != A,则创建并插入 B,删除 A;以此类推,创建并插入 A、D、C,删除 B、C、D


    Element Diff 02.png
  • 执行过程:B、D 不做任何操作,A、C 进行移动操作


diff 算法总结:

  1. 保持完整的结构,有利于性能的提升

  2. 尽量使用相同类型的组件

  3. 在进行 Element 或Component 级别对比的时候,为了提高对比的效率, React 推荐我们为每个 for 循环创建出来的元素或者组件,提供一个唯一的 key;

  4. Tree diff :将新旧两棵 DOM 树,按照层级对应的关系,这样只需要对树进行一次遍历,就能够找到哪些元素是需要更新的;

  5. Component Diff: 在对比每一层的时候,每一层都有自己的组件, 那么组件之间的对比,叫做 Component diff , 对比的方式,就是查看两个组件的类型是否相同,如果相同,则暂时认为不需要更新,如果类型不同,则表示更新(先把旧的组件删除,再创建一个新的组件,插入到刚才删除的位置);

  6. Element Diff:如果新旧 DOM 树中的组件类型相同,会继续比较这两个组件内部的元素是否也相同,如果元素发生了改变,则找到需要修改的元素,有针对性的修改,这种组件内部元素级别的对比叫: Element Diff;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容