React 中最值得称道的部分莫过于 Virtual DOM 与 diff 的完美结合,特别是其高效的 diff 算法,让用户可以无需顾忌性能问题而”任性自由”的刷新页面,让开发者也可以无需关心 Virtual DOM 背后的运作原理,因为 React diff 会帮助我们计算出 Virtual DOM 中真正变化的部分,并只针对该部分进行实际 DOM 操作,而非重新渲染整个页面,从而保证了每次操作更新后页面的高效渲染,因此 Virtual DOM 与 diff 是保证 React 性能口碑的幕后推手。

1 diff 策略

  1. Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计
  2. 拥有相同类的两个组件将会生成相似的树形结构,拥有不同类的两个组件将会生成不同的树形结构
  3. 对于同一层级的一组子节点,它们可以通过唯一id进行区分

以上三个策略,React 分别对 tree diff、component diff 以及 element diff 进行算法优化,事实也证明这三个前提策略是合理且准确的,它保证了整体界面构建的性能。

2 tree diff

基于策略一,React 对树的算法进行了简洁明了的优化,即对树进行分层比较,两棵树只会对同一层次的节点进行比较。

既然 DOM 节点跨层级的移动操作少到可以忽略不计,针对这一现象,React 通过 updateDepth 对 Virtual DOM 树进行层级控制,只会对相同颜色方框内的 DOM 节点进行比较,即同一个父节点下的所有子节点。当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。这样只需要对树进行一次遍历,便能完成整个 DOM 树的比较。

如果出现dom节点跨层级的移动操作,因为该节点已经不在原来的dom树层, 所以会直接删除该节点,在移动后的dom层重建该节点, 可见这种操作的性能代价非常大,所以不推荐这样做。 可以通过css样式控制节点的隐藏和显示来代替节点跨层级移动的操作。

3 component diff

React 是基于组件构建应用的,对于组件间的比较所采取的策略也是简洁高效。

如果是同一类型的组件,按照原策略继续比较 virtual DOM tree。

如果不是,则将该组件判断为 dirty component,从而替换整个组件下的所有子节点。

对于同一类型的组件,有可能其 Virtual DOM 没有任何变化,如果能够确切的知道这点那可以节省大量的 diff 运算时间,因此 React 允许用户通过 shouldComponentUpdate() 来判断该组件是否需要进行 diff。

如下图,当 component D 改变为 component G 时,即使这两个 component 结构相似,一旦 React 判断 D 和 G 是不同类型的组件,就不会比较二者的结构,而是直接删除 component D,重新创建 component G 以及其子节点。虽然当两个 component 是不同类型但结构相似时,React diff 会影响性能,但正如 React 官方博客所言:不同类型的 component 是很少存在相似 DOM tree 的机会,因此这种极端因素很难在实现开发过程中造成重大影响的。

4 element diff

当节点处于同一层级时,React diff 提供了三种节点操作,分别为:INSERT_MARKUP(插入)、MOVE_EXISTING(移动)和 REMOVE_NODE(删除)。

INSERT_MARKUP,新的 component 类型不在老集合里, 即是全新的节点,需要对新节点执行插入操作。
MOVE_EXISTING,在老集合有新 component 类型,且 element 是可更新的类型,generateComponentChildren 已调用 receiveComponent,这种情况下 prevChild=nextChild,就需要做移动操作,可以复用以前的 DOM 节点。
REMOVE_NODE,老 component 类型,在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作,或者老 component 不在新集合里的,也需要执行删除操作。
开发者对同一层级的子节点,可以添加唯一索引进行区分,这样在diff时,涉及到只是位置变化的,可以只移动元素,避免删除创建等重复的操作。

一图看懂React diff相关推荐

  1. 一张图看懂React生命周期

    2019独角兽企业重金招聘Python工程师标准>>> 一.创建时 componentWillMount 初始化组建,render方法之前执行,官方不建议做数据请求 componen ...

  2. 鸿蒙系统的结构图,一图看懂鸿蒙系统中的JS开发框架!

    原标题:一图看懂鸿蒙系统中的JS开发框架! " 前端这两年玩起来了三国杀,Vue,React,Angular 三足鼎立,其中 Vue 派系在国内打的 Angular 找不到北了. 因此,小程 ...

  3. 一篇文章一张思维导图看懂Android学习最佳路线

    一篇文章一张思维导图看懂Android学习最佳路线 先上一张android开发知识点学习路线图思维导图 Android学习路线从4个阶段来对Android的学习过程做一个全面的分析:Android初级 ...

  4. 一张图看懂图像识别算法发展历史

    一张图看懂图像识别算法发展历史

  5. 一图看懂新一代人工智能知识体系大全

    来源:财经头条 摘要:人工智能的发展离不开基础支持层和技术层,基础支持层包括大数据.计算力和算法:技术层包括计算机视觉.语音识别和自然语言处理.人工智能的技术本质是什么,本文会详细分析. 人工智能的发 ...

  6. 一图看懂windows11新功能

    [欢迎关注微信公众号:厦门微思网络] 微思网络(官网):https://www.xmws.cn/ 微软Windows 11操作系统还没有正式推出,不过加入"预览体验计划"可以抢先体 ...

  7. sdn体系的三个平面_十张图看懂SDN与NFV的区别与联系?

    原标题:十张图看懂SDN与NFV的区别与联系? 专业的人说的很准确但是普通人难以理解,常常记不住,分不清,不专业的人往往又说的差点意思.无意间,笔者在领英上看到一个介绍SDN/NFV区别的公开文档,内 ...

  8. 一图看懂hadoop分布式文件存储系统HDFS工作原理

    一图看懂hadoop分布式文件存储系统HDFS工作原理 转载于:https://www.cnblogs.com/AlexQY/p/9856477.html

  9. 【转】几张图看懂列式存储

    几张图看懂列式存储 转载于:https://www.cnblogs.com/apeway/p/10870211.html

最新文章

  1. CCNA实验之--三层交换
  2. linux之find命令详解
  3. pythonhtml内容比较_Python使用difflib模块比较两个文件内容异同,同时输出html易浏览...
  4. 谷歌加载web workers问题
  5. leetcode--数组(Easy)
  6. C#LeetCode刷题之#605-种花问题( Can Place Flowers)
  7. 笔记 | 《机器学习》中计算学习理论(下)
  8. 【Python自动化运维之路Day6】
  9. java word另存为_Java 网页html转为word并保存为doc文件
  10. 如何锻炼一个人处理问题的能力?
  11. 带有第三方工具的Spring Boot Initilizr
  12. MAC:一个数据缓冲区,作为参数传递到另外一个函数就崩溃
  13. jQuery常用插件
  14. Poi操作Excel,保留格式的情况下插入行
  15. 前端速成:双月Java之旅(week3)_day2
  16. 32强鹏城逐战!“共筑梦想、创赢未来” 2021年绿色产业创新创业大赛深圳赛区比赛精彩上演
  17. python作业——SVM预测交通流量
  18. Intelligent Parking Building
  19. spa:单页web应用(介绍,实现思路及技术点,路由,router-link相关属性)
  20. 《高级语言程序设计》习题集

热门文章

  1. win7 安装vs2013 出现“已阻止安装程序”IE10的问题
  2. Android 微博分享失败问题
  3. 这篇游戏配音教程快收下,轻松进行配音
  4. R语言之代码提速(对老虎机案例进行优化)
  5. 还原精灵引起的系统不能进入
  6. 怕是诸葛先生听了也要为之动容吧~
  7. tinyxml2存储xml数据简单高效
  8. linux poll 作用,Linux中poll机制的理解
  9. shell脚本执行SQL
  10. one night in 北京-信乐团