南京网站排名/长尾关键词搜索网站
此篇文章所讨论的是 React 16 以前的 Diff 算法。而 React 16 启用了全新的架构 Fiber,相应的 Diff 算法也有所改变,本片不详细讨论Fiber。
fiber架构是为了支持react进行可中断渲染,降低卡顿,提升流畅度。
react16之前的版本,diff虚拟dom时候是一口气完成的。这可能造成卡顿,因为人眼可识别的帧率是1s 60帧,即16ms一帧,如果diff时间超过16ms,阻塞渲染,就会感觉卡顿。
为了避免这种情况,需要让diff操作不超过16ms,如果超过16ms,就先暂停,让给浏览器进行渲染操作,后续渲染间隙再继续diff。
fiber架构就是为了支持这种“可中断渲染”而涉及的。fiber tree是一种数据结构,它把虚拟dom tree连接成一个链表,从而可以让遍历操作可以支持断点重启。
React 的核心思想
React 最为核心的就是 Virtual DOM 和 Diff 算法。React 在内存中维护一颗虚拟 DOM 树,当数据发生改变时(state & props),会自动的更新虚拟 DOM,获得一个新的虚拟 DOM 树,然后通过 Diff 算法,比较新旧虚拟 DOM 树,找出最小的有变化的部分,将这个变化的部分(Patch)加入队列,最终批量的更新这些 Patch 到实际的 DOM 中。
传统 diff 算法
将一颗 Tree 通过最小操作步数映射为另一颗 Tree,这种算法称之为 Tree Edit Distance(树编辑距离)。如图:
上图中,最小操作步数(编辑距离)为 3:
- 删除 ul 节点
- 添加 span 节点
- 添加 text 节点
而 Tree Edit Distance 算法从 1979 年到 2011年,经过了30多年的发展演变,其时间复杂度最终被优化到 O(n^3),其发展历程大致如下(n 是树中节点的总数):
- 1979年,Tai 提出了次个非幂级复杂度算法,时间复杂度为 O(m3*n3)
- 1989年,Zhang and Shasha 将 Tai 的算法进行优化,时间复杂度为 O(m2*n2)
- 1998年,Klein 将 Zhang and Shasha 的算法再次优化,时间复杂度为 O(n^2*m*log(m))
- 2009年,Demiane 提出最坏情况下的计算公式,将时间复杂度控制在 O(n^2*m*(1+log(m/n)))
- 2011年,Pawlik and N.Augsten 提出适用于所有形状的树的算法,并将时间复杂度控制在 O(n^3)
这里不会展开讨论 Tree Edit Distance 算法的具体实现和原理,有兴趣可以直接看这篇论文 A Robust Algorithm for the Tree Edit Distance
React diff
传统 diff 算法其时间复杂度最优解是 O(n^3),那么如果有 1000 个节点,则一次 diff 就将进行 10 亿次比较,这显然无法达到高性能的要求。而 React 通过大胆的假设,并基于假设提出相关策略,成功的将 O(n^3) 复杂度的问题转化为 O(n) 复杂度的问题。
(1)两个假设
为了优化 diff 算法,React 提出了两个假设:
- 两个不同类型的元素会产生出不同的树
- 开发者可以通过
key
prop 来暗示哪些子元素在不同的渲染下能保持稳定
(2)三个策略
基于这上述两个假设,React 针对性的提出了三个策略以对 diff 算法进行优化:
- Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计
- 拥有相同类型的两个组件将会生成相似的树形结构,拥有不同类型的两个组件将会生成不同树形结构
- 对于同一层级的一组子节点,它们可以通过唯一 key 进行区分
(3)diff 具体优化
基于上述三个策略,React 分别对以下三个部分进行了 diff 算法优化
- tree diff
- component diff
- element diff
tree diff
React 只对虚拟 DOM 树进行分层比较,不考虑节点的跨层级比较。如下图:
如上图,React 通过 updateDepth 对虚拟 Dom 树进行层级控制,只会对相同颜色框内的节点进行比较,根据对比结果,进行节点的新增和删除。如此只需要遍历一次虚拟 Dom 树,就可以完成整个的对比。
如果发生了跨层级的移动操作,如下图:
通过分层比较可知,React 并不会复用 B 节点及其子节点,而是会直接删除 A 节点下的 B 节点,然后再在 C 节点下创建新的 B 节点及其子节点。因此,如果发生跨级操作,React 是不能复用已有节点,可能会导致 React 进行大量重新创建操作,这会影响性能。所以 React 官方推荐尽量避免跨层级的操作。
component diff
React 是基于组件构建的,对于组件间的比较所采用的策略如下:
- 如果是同类型组件,首先使用
shouldComponentUpdate()
方法判断是否需要进行比较,如果返回true
,继续按照 React diff 策略比较组件的虚拟 DOM 树,否则不需要比较 - 如果是不同类型的组件,则将该组件判断为 dirty component,从而替换整个组件下的所有子节点
如上图,虽然组件 C 和组件 H 结构相似,但类型不同,React 不会进行比较,会直接删除组件 C,创建组件 H。
从上述 component diff 策略可以知道:
- 对于不同类型的组件,默认不需要进行比较操作,直接重新创建。
- 对于同类型组件, 通过让开发人员自定义
shouldComponentUpdate()
方法来进行比较优化,减少组件不必要的比较。如果没有自定义,shouldComponentUpdate()
方法默认返回true
,默认每次组件发生数据(state & props)变化时,都会进行比较。
element diff
element diff 涉及三种操作:移动、创建、删除。对于同一层级的子节点,对于是否使用 key 分别进行讨论。
对于不使用 key 的情况,如下图:
React 对新老同一层级的子节点对比,发现新集合中的 B 不等于老集合中的 A,于是删除 A,创建 B,依此类推,直到删除 D,创建 C。这会使得相同的节点不能复用,出现频繁的删除和创建操作,从而影响性能。
对于使用 key 的情况,如下图:
React 首先会对新集合进行遍历,通过唯一 key 来判断老集合中是否存在相同的节点,如果没有则创建,如果有的,则判断是否需要进行移动操作。并且 React 对于移动操作也采用了比较高效的算法,使用了一种顺序优化手段,这里不做详细讨论。
从上述可知,element diff 就是通过唯一 key 来进行 diff 优化,通过复用已有的节点,减少节点的删除和创建操作。
(4)如何进行 diff
上面已经说完了 React 的 diff 策略和具体优化,这里简单谈一下 React 是如何应用这些策略来进行 diff :
React 是基于组件构建的,首先可以将整个虚拟 DOM 树,抽象为 React 组件树(每一个组件又是由一颗更小的组件树构成,依次类推),将 React diff 策略应用比较这颗组件树,若其中某个组件需要进行比较,将这个组件看成一颗较小的组件树,继续用 React diff 策略比较这颗较小的组件树,依次类推,直到层次遍历完所有的需要比较的组件。
小结
React 通过大胆的假设,制定对应的 diff 策略,将 O(n3) 复杂度的问题转换成 O(n) 复杂度的问题
- 通过分层对比策略,对 tree diff 进行算法优化
- 通过相同类生成相似树形结构,不同类生成不同树形结构以及
shouldComponentUpdate
策略,对 component diff 进行算法优化 - 通过设置唯一 key 策略,对 element diff 进行算法优化
综上,tree diff 和 component diff 是从顶层设计上降低了算法复杂度,而 element diff 则在在更加细节上做了进一步优化。
相关文章:

react16之前diff算法的理解和总结
此篇文章所讨论的是 React 16 以前的 Diff 算法。而 React 16 启用了全新的架构 Fiber,相应的 Diff 算法也有所改变,本片不详细讨论Fiber。 fiber架构是为了支持react进行可中断渲染,降低卡顿,提升流畅度。 react16之前的版本&…...

JavaEE初阶(1)(冯诺依曼体系、CPU、CPU基本原理、如何衡量CPU的好坏?指令、操作系统、操作系统“内核”)
目录 冯诺依曼体系(Von Neumann Architecture) CPU CPU基本原理: 如何衡量CPU的好坏? 1、主频(时钟速度): 2、核心数: 指令 操作系统 操作系统“内核” 冯诺依曼体系&#x…...

记录在yapi上传接口的问题
sorry ,upload api error cause:请求参数 data.path 不应少于 1 个字符 自己在写的代码中使用到了DeleteMapping DeleteMapping("/deleteCart/{skuId}")public Result deleteCart(PathVariable Long skuId,HttpServletRequest request){报上面的错误,原因…...

DevOps管理软件生命周期
整体的软件开发流程 PLAN:开发团队根据客户的目标制定开发计划 CODE:根据PLAN开始编码过程,需要将不同版本的代码存储在一个库中。GIT,SVN BUILD:编码完成后,需要将代码构建并且运行。MAVEN TEST:成功构建…...

快速解决 adb server version doesn‘t match this client
这个问题是由于电脑上安装了多个版本的adb工具,客户端和服务端的版本不一致,无法正常通信导致。最快的解决方法就是将Android SDK中adb复制到系统目录下。 操作步骤如下: 1. 查看adb版本和路径 执行adb version,如下࿰…...

【更新至2022年】2000-2022年全国31省市以2000年为基期的实际GDP、名义GDP、GDP平减指数数据(含原始数据+计算过程+计算结果)
2000-2022年31省市名义GDP 实际GDP GDP平减指数 1、时间:2000-2022 2、范围:31省市 3、来源:GJ统计J和统计NJ 4、指标:名义GDP、地区生产总值指数(上年100)、实际GDP(以2000年为基期&#x…...

【LeetCode】剑指 Offer <二刷>(5)
目录 题目:剑指 Offer 10- II. 青蛙跳台阶问题 - 力扣(LeetCode) 题目的接口: 解题思路: 代码: 过啦!!! 题目:剑指 Offer 11. 旋转数组的最小数字 - 力…...

rtsp 拉流 gb28181 收流 经AI 算法 再生成 rtsp server (一)
1、 rtsp 工具 1 vlc 必备工具 2 wireshark 必备工具 3 自己制作的工具 player 使用tcp 拉流,不自己写的话,使用ffmpeg 去写一个播放器就行 4 live555 编译好live555, 将live555的参数修改以下,主要是缓存大小 文章使用c 来写一…...

Jmeter系列-环境部署、详细介绍、安装目录介绍(1)
环境部署 官网下载Jmeter http://jmeter.apache.org/下载最新版本的 JMeter,解压文件到任意目录 安装JDK,配置Java环境 1、下载(注意选择操作系统对应的位数32/64) 官网 :http://www.oracle.com 2、安装࿰…...

更换 yum 阿里源 - 手把手教你怎么配置,在也不需要求别人了 - 看懂一个就相当于看懂了其他的linux系统
更换阿里源 我的是centos8 当然 centos7 也可以换 后面有更详细的怎么配 ,再也不用求别人怎么弄了 最直接的方式 直接复制 执行 centos7 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo或者 wget -O /etc/yum.repos.…...

966SEO扫地僧站群·万能HTML模板[V1.9.1]
扫地僧站群万能HTML模板是一款站点管理软件,其主要特点是可以将原始的html模板放入程序中,无需编写任何标签,程序会全自动替换处理,从而快速构建出一个完整的网站,这种模式相对于传统的网站建设方式更加快速、简单,同时可以大幅度降低网站建设的成本和难度.服务器及域名量的配置…...

angular:html2canvas对ion-avatar节点渲染不正确
问题: 如题 解决办法: 简单实现头像遮罩 <div class"ion-avatar" style"width: 40px; height: 40px; border-radius: 50%; overflow: hidden"><img src"" alt""/> </div><style>.ion-…...

使用dockerfile文件部署Python+PyWebIO项目
1、安装docker 教程详见之前的内容。https://blog.csdn.net/weixin_44691253/category_12101661.html 2、打包好Python项目 之前的文章中有提到我编写测试工具使用的框架:PythonRequestsPyWebIO框架详解,编写测试工具提高团队测试效率 打包项目时&am…...

【web开发】5.Mysql及python代码执行数据库操作
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、MYSQL二、MySQL管理查看已有数据库创建数据库删除数据库进入数据库创建表删除表展示表的行列插入数据查看表中的数据删除数据修改数据 三、python代码执行数据库…...

Android学习之路(13) Handler详解
1. 简介 Handler是一套 Android 消息传递机制,主要用于线程间通信。 用最简单的话描述: handler其实就是主线程在起了一个子线程,子线程运行并生成Message,Looper获取message并传递给Handler,Handler逐个获取子线程中的Message.…...

介绍一些开发用到的工具
Sourcetree :Git 界面操作工具,真心好用 uTool:效率工具平台,可以了解一下,提供了很多强大的工具,加强了对电脑的操作 MobaXterm:带有 X11 服务器、选项卡式 SSH 客户端、网络工具等的增强型 Wi…...

【笔试真题记录】2023滴滴编程第二题
题目: 现在有n个由大写英文字符组成的字符串,且这些字符串不会互相包含,也不会相等。现在想知道有哪些字符串满足如下条件。设满足条件的字符串为S,存在其他的两个字符串拼接在一起后,能通过去除一个非空前缀和一个非空…...

中国ui设计师年终工作总结
一、萌芽阶段 记得初次应聘时,我对公司的认识仅仅局限于行业之一,对UI设计师一职的认识也局限于从事相对单纯的界面的设计创意和美术执行工作。除此之外,便一无所知了。所以,试用期中如何去认识、了解并熟悉自己所从事的行业&…...

CSS 滚动驱动动画 scroll()
CSS 滚动驱动动画 scroll() animation-timeline 通过 scroll() 指定可滚动元素与滚动轴来为容器动画提供一个匿名的 scroll progress timeline. 通过元素在顶部和底部(或左边和右边)的滚动推进 scroll progress timeline. 并且元素滚动的位置会被转换为百分比, 滚动开始被转化为…...

基于Java+SpringBoot+Vue前后端分离在线考试系统设计和实现
博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…...

nvm管理多个版本的nodejs
1. 已经安装过nodejs在安装nvm的步骤 1.安装nvmhttps://github.com/coreybutler/nvm-windows/releases 2.nvm安装位置 2.nvm管理的nodejs安装位置 4.最终的安装结构 备注:nodejs安装 2.使用nvm安装管理nodejs 2.1配置下载镜像: 找到nvm安装路径…...

LeetCode 1658. 将 x 减到 0 的最小操作数
题目链接 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 题目解析 有种说法叫做,正难则反。我们直接去按照题目意思去求很难去理解与操作,但是我们换种思想就会简单许多。我们让整个数组的和减去x得到一个target,…...

Rasa 3.1 机器学习一构建标准的对话
1、控制请求(domain.yml) version: "3.1"intents:- hellosession_config:session_expiration_time: 60carry_over_slots_to_new_session: true2、规则制定(rules.yml) version: "3.1" rules:- rule: havebsteps:- intent: hello- action: utter_hello3、…...

MySQL的概述、版本、安装过程
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 目录 一、MySQL的概述 二、MySQL的版本 三、MySQL的下载与安装 前言 本文将来谈谈MySQL的概述,MySQL的版本,以及它…...

leetcode:58. 最后一个单词的长度
题目: 函数原型: int lengthOfLastWord(char * s) 解析: 求最后一个单词的长度,我们有两种思路 第一种思路: 逆向求,先设置一个字符串下标index,定位到最后一个单词的最后一个字符。再一个设置长…...

Electron 两个线程
Electron:它允许使用最初为Web应用程序开发的前端和后端组件开发桌面GUI应用程序:后端的Node.js运行时和前端的Chromium。 每个Electron应用都有两个线程:一个是主线程(处理应用窗口和启动),另一个是渲染线…...

基于YOLOv8和WiderFace数据集的人脸目标检测系统(PyTorch+Pyside6+YOLOv8模型)
摘要:基于YOLOv8和WiderFace数据集的人脸目标检测系统可用于日常生活中检测与定位人脸目标,利用深度学习算法可实现图片、视频、摄像头等方式的目标检测,另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算…...

《消息队列》专栏介绍
《消息队列》专栏介绍 目录 《消息队列》专栏介绍专栏导言什么是消息队列呢?应用场景(作用) 为什么要用消息队列呢?异步处理削峰填谷 举个例子 分布式消息队列的优势 应用解耦优点发布订阅优点 分布式消息队列应用场景不同消息队列…...

各类工具使用详情【持续更新】
详解nc命令 https://blog.csdn.net/qq_42875470/article/details/114778326 xray工具使用 sqlmap工具使用 burp工具使用 nmap工具使用 appscan工具使用 fscan工具使用...

docker容器的安装和基础练习
目录 一.安装docker服务,配置镜像加速器 二.下载系统镜像(Ubuntu、 centos) 三.基于下载的镜像创建两个容器 (容器名一个为自己名字全拼,一个为首名字字母) 四.容器的启动、 停止及重启操作 五.怎么查…...