react16之前diff算法的理解和总结

news2024/11/26 2:10:31

此篇文章所讨论的是 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:

  1. 删除 ul 节点
  2. 添加 span 节点
  3. 添加 text 节点

而 Tree Edit Distance 算法从 1979 年到 2011年,经过了30多年的发展演变,其时间复杂度最终被优化到 O(n^3),其发展历程大致如下(n 是树中节点的总数):

  1. 1979年,Tai 提出了次个非幂级复杂度算法,时间复杂度为 O(m3*n3)
  2. 1989年,Zhang and Shasha 将 Tai 的算法进行优化,时间复杂度为 O(m2*n2)
  3. 1998年,Klein 将 Zhang and Shasha 的算法再次优化,时间复杂度为 O(n^2*m*log(m))
  4. 2009年,Demiane 提出最坏情况下的计算公式,将时间复杂度控制在 O(n^2*m*(1+log(m/n)))
  5. 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 提出了两个假设:

  1. 两个不同类型的元素会产生出不同的树
  2. 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定

(2)三个策略

基于这上述两个假设,React 针对性的提出了三个策略以对 diff 算法进行优化:

  1. Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计
  2. 拥有相同类型的两个组件将会生成相似的树形结构,拥有不同类型的两个组件将会生成不同树形结构
  3. 对于同一层级的一组子节点,它们可以通过唯一 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 策略可以知道:

  1. 对于不同类型的组件,默认不需要进行比较操作,直接重新创建。
  2. 对于同类型组件, 通过让开发人员自定义shouldComponentUpdate()方法来进行比较优化,减少组件不必要的比较。如果没有自定义,shouldComponentUpdate()方法默认返回true,默认每次组件发生数据(state & props)变化时,都会进行比较。

element diff

element diff 涉及三种操作:移动、创建、删除。对于同一层级的子节点,对于是否使用 key 分别进行讨论。

对于不使用 key 的情况,如下图:

React 对新老同一层级的子节点对比,发现新集合中的 B 不等于老集合中的 A,于是删除 A,创建 B,依此类推,直到删除 D,创建 C。这会使得相同的节点不能复用,出现频繁的删除和创建操作,从而影响性能。

对于使用 key 的情况,如下图:

使用 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 则在在更加细节上做了进一步优化。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/974673.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是standard cell (标准单元) ?

参考文章: 聊一聊芯片后端的标准单元-standard cell - 知乎 (zhihu.com) standard cell中的7T和9T中的"T"指的是什么?或者是什么的缩写? - Layout讨论区 - EETOP 创芯网论坛 (原名:电子顶级开发网) - 数字后端基本概念介…

qemu-system-x86_64 命令创建虚拟机,报gtk initialization failed的

因为是ssh命令行启动,增加--nographic # /opt/debug/bin/qemu-system-aarch64 -machine virt-6.2 -qmp tcp:localhost:1238,server,nowait --nographic configure accelerator virt-6.2 start machine init start cpu init start add rom file: virtio-net-pci…

GIT实战篇,教你如何使用GIT可视化工具

系列文章目录 手把手教你安装Git,萌新迈向专业的必备一步 GIT命令只会抄却不理解?看完原理才能事半功倍! 快速上手GIT命令,现学也能登堂入室 GIT实战篇,教你如何使用GIT可视化工具 系列文章目录一、GIT有哪些常用工具…

漆包线工厂云MES解决方案

漆包线行业老板痛点: 1.漆包线比较传统的行业,一般都是靠人工去管理,老板想及时知道工厂的生产,销售、出入库、库存情况; 2.型号多称重打印易错,没有系统前 :称重打印,出入库&#x…

解决github连接不上的问题

改 hosts 我们在浏览器输入 GitHub 的网址时,会向 DNS 服务器发送一个请求,获取到 GitHub 网站所在的服务器 IP 地址,从而进行访问。 就像你是一名快递员,在送快递前要先找中间人询问收件人的地址。而 DNS 就是这个告诉你目标地址…

java开发之个微机器人的二次开发

简要描述: 取消消息接收 请求URL: http://域名地址/cancelHttpCallbackUrl 请求方式: POST 请求头Headers: Content-Type:application/json 参数: 参数名类型说明codestring1000成功,1…

顶尖211“小清华”!强过985,不要错过它!

一、学校及专业介绍 西安电子科技大学(Xidian University),简称“西电” ,位于陕西省西安市,是中央部属高校,直属于教育部,为全国重点大学,位列国家“双一流”“211工程”&#xff…

宝塔面板开心版出问题升级到正版的解决方案,有效解决TypeError: ‘NoneType‘ object is not subscriptable

服务器之前图开心装了个宝塔面板的开心版,前几天突然出现问题,报错TypeError: ‘NoneType’ object is not subscriptable。没法正常打开软件商店,也没法修复和升级系统,很烦躁。因为里面很多业务还在跑,实在不想重装。…

呜呜呼呼无无话

姓名和手机号脱敏 function nameDesen(value) {if (!value) return return value.substring(0, 1) new Array(value.length).join(*) } const bklnameDesen(宝矿力) console.log(bkl) //宝**function telephoneDesen(value) {if (!value) return value value.toString()ret…

伦敦金投资中挂单的优势

在伦敦金交易中,其实挂单具有无可比拟的优势?首先,如果我们不是全职的投资者,我们在交易时间内可能有其他的工作,那么挂单就可以帮助我们捕捉到市场的机会,即便我们不一定会坐在电脑面前,也可以…

Vue中的指令

指令 指令 (Directives) 是带有 v- 前缀的特殊 attribute。指令 attribute 的值预期是单个 JavaScript 表达式。指令的职责是,当表达式的值改变时,将其产生的连带影响,响应式地作用于 DOM。 常用指令预期简短介绍v-showany显示隐藏元素&…

旅游攻略APP外包开发功能

旅游攻略APP是帮助旅行者计划和享受旅行的工具,下面列出了一些常见的旅游攻略APP功能,以及在上线这类应用时需要注意的问题,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 常见…

6517B|吉时利keithley 6517B高阻表

181/2461/8938Keithley 6517B 静电计 / 高阻表是全球科研实验室灵敏测量的标准。吉时利在弱电测量方面拥有 60 多年的专业经验,吉时利静电计能够可靠地测量最低 10 aA (1010-18A) 电流、最低 1 fC 电荷,并支持最高 1018Ω 的电阻测量。6517B 还能够测量高…

自动化驱动程序管理

在部署操作系统时,每次都从下载和分发所需的驱动程序中实现真正的独立性可能是一场艰苦的战斗。特别是具有硬件多样化的环境,并且需要支持新的硬件类型时。借助 OS Deployer,可以对所有端点使用一个映像,无论品牌和型号如何&#…

Java版本工程行业管理系统源码-专业的工程管理软件

Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下: 首页 工作台:待办工作、消息通知、预警信息,点击可进入相应的列表 项目进度图表:选择(总体或单个)项目显示1…

机器学习算法详解1:基础知识合集

机器学习算法详解1:基础知识合集 前言 ​ 本系列主要对机器学习上算法的原理进行解读,给大家分享一下我的观点和总结。 本篇前言 ​ 开一个新系列,另外现在开学了,忙起来了,所以更新会很慢。 目录结构 文章目录 机器学…

SI24R1/NRF24L01P引脚及软硬件中文开发资料

NRF24L01P芯片兼容通信。从而被打上了国产NRF24L01P的标签,更有甚者居然磨掉芯片原本的SI24R1的LOGO打成NRF24L01P,给很多客户产生了很多不必要的损失。大家定向的理解,国产的东西总是会比国外进口的相差到哪里哪里,如此云云。其实…

冠达管理:融创中国获纳入港股通标的,股价涨幅超20%

到发稿,港股融创我国股价报1.53港元,涨21.43%。 9月5日,港股融创我国高开,到发稿,股价报1.53港元,涨21.43%。 ​ 消息面上,根据上交所、深交所公告,港通下港股通标的名单发生调整…

电商为什么要做小程序商城?

微信小程序出现之后,便迅速在网络上走红,并且开放很多接口,最重要的是,微信小程序可以和公众号密切关联消息,这样给企业带来了更多商机。特别是微信小程序商城得到了微信平台的大力扶持,这样一来&#xff0…

企业做微信小程序开发的好处

一、引言 在移动优先的时代,微信小程序为企业提供了新的营销方式和用户交互方式。微信小程序具有轻便、易用、可跨平台等特性,使得企业可以快速触达广大用户。本文将详细探讨企业做微信小程序开发的好处。 二、微信小程序对企业的好处 增加品牌知名度&…