首页 > 编程语言 >React 中的 diff 算法

React 中的 diff 算法

时间:2024-10-07 18:23:27浏览次数:1  
标签:DOM React 算法 虚拟 组件 diff 节点

React diff

  1. 为什么使用虚拟 DOM ?
    浏览器在处理 DOM 的时候会很慢,处理 JavaScript 会很快,页面复杂的时候,频繁操作 DOM 会有很大的性能开销(每次数据变化都会引起整个 DOM 树的重绘和重排)。
    为了避免频繁操作 DOM,React 会维护两个虚拟 DOM,如果有数据更新,会借此计算出所有修改的状态集中到一起,统一更新一次虚拟 DOM。
  2. diff 是什么?
    React 会维护两个虚拟 DOM,如果有数据更新,会借此计算出所有修改的状态,然后将这些变化更新到真实 DOM 上,diff 算法就是比较两个虚拟 DOM 树的策略。
  3. 虚拟 DOM 一定会提高性能吗?
    不一定。
    因为虚拟 DOM 虽然会减少 DOM 操作,但也无法避免 DOM 操作。
    它的优势是在于 diff 算法和批量处理策略,将所有的 DOM 操作搜集起来,一次性去改变真实的 DOM,但在首次渲染上,虚拟 DOM 会多了一层计算,消耗一些性能,所以有可能会比 html 渲染的要慢

传统 diff 算法

通过循环递归对节点进行依此对比,其算法复杂度达到了O(n^ 3),也就是说,如果展示一千个节点,就要计算十亿次。

React v16 优化

React通过三大策略完成了优化:

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

分别对应:tree diff、component diff、element diff

tree diff

同级比较:在对比的过程中,如果发现节点不在了,会完全删除不会对其他地方进行比较,这样只需要对树遍历一次就OK了

component diff

两种策略:

  1. 相同类型的组件

按照层级比较继续比较虚拟DOM树即可。

特殊情况:当组件A如果变化为组件B的时候,有可能虚拟DOM并没有任何变化,所以用户可以通过shouldComponentUpdate() 来判断是否需要更新,判断是否计算

  1. 不同类型的组件

React会直接判定该组件为dirty component(脏组件),无论结构是否相似,只要判断为脏组件就会直接替换整个组件的所有节点

element diff

节点比较,对于同一层级的一子自节点,通过唯一的key进行比较

当所有节点处以同一层级时,React 提供了三种节点操作:

  1. 插入(INSERT_MARKUP):新的 component 类型不在老集合里, 即是全新的节点,需要对新节点执行插入操作。
  2. 移动(MOVE_EXISTING):在老集合有新 component 类型,且 element 是可更新的类型,generateComponentChildren 已调用 receiveComponent,这种情况下prevChild=nextChild,就需要做移动操作,可以复用以前的 DOM 节点。(传统 diff 检测到不相同就直接删除重建)
  3. 删除(REMOVE_NODE):老 component 类型,在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作,或者老 component 不在新集合里的,也需要执行删除操作。

具体的 diff 过程
遍历新的一层节点,使用 lastIndex 记录每次比较后的节点最新索引,使用 index 表示在旧的一层中该节点的索引。

在新的一层中,如果发现该节点存在过,通过 key 找到该节点在旧的一层中的坐标 index,如果 index < lastIndex 就移动该节点,否则不动,然后更新 lastIndex = max(lastIndex, index)

如果该节点没有存在过,就新建,但是不更新 lastIndex

相同位置

插入新节点

当最后一个节点移动到第一个位置时,可能出现的问题(所有节点都需要移动)

为什么不能使用 index 作为 key 值?
因为通过 key 找到的两个节点不相同,需要删除重建,使用唯一值(比如id)描述每个节点,这样起到 diff 算法的作用。
下面的例子中的节点全都需要重建,因为每次通过 key 找到的节点都不相同,无法发挥 diff 算法的作用

参考

https://juejin.cn/post/7116326409961734152

标签:DOM,React,算法,虚拟,组件,diff,节点
From: https://www.cnblogs.com/zjy4fun/p/18450398

相关文章

  • Day 24 贪心算法part02| LeetCode 122.买卖股票的最佳时机II,55.跳跃游戏,45.跳跃游戏II
    122.买卖股票的最佳时机II局部最优:每天的正利润全局最优:每天的正利润之和121.买卖股票的最佳时机classSolution{publicintmaxProfit(int[]prices){intres=0;for(inti=1;i<prices.length;i++){i......
  • [Vue] Reactive note
    <template><div> count:{{count}} </div><div> doubled:{{doubledCount}} </div> <button@click="increase">increase</button></template><scriptsetup>import{computed,ref,......
  • react 知识点汇总(非常全面)
    React是一个用于构建用户界面的JavaScript库,由Facebook开发并维护。它的核心理念是“组件化”,即将用户界面拆分为可重用的组件。React的组件通常使用JSX(JavaScriptXML)。JSX是一种JavaScript语法扩展,允许开发者在JavaScript代码中编写类似HTML的结构。1、初识reac......
  • What is the difference between a Homemaker and a Housewife?
    Theterms"homemaker"and"housewife"areoftenusedinterchangeably,buttheycancarrydifferentconnotationsandimplications:HomemakerDefinition:Ahomemakerisgenerallysomeonewhomanagesahouseholdandtakescareofhome-re......
  • 代码随想录算法训练营day7|● 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ●
    学习资料:https://programmercarl.com/0015.三数之和.html#其他语言版本学习记录:454.四数相加(hash_dict,前两个数一组遍历a+b,后两个数一组遍历找0-(a+b))点击查看代码classSolution:deffourSumCount(self,nums1:List[int],nums2:List[int],nums3:List[int],nums4:......
  • 代码随想录算法训练营 | 56. 合并区间,738.单调递增的数字
    56.合并区间题目链接:56.合并区间文档讲解︰代码随想录(programmercarl.com)视频讲解︰合并区间日期:2024-10-06想法:重叠区间类似问题Java代码如下:classSolution{publicint[][]merge(int[][]intervals){List<int[]>res=newArrayList<>();Arra......
  • C++ 算法学习——1.8 悬线法
    1.问题引入:对于一个矩形图,图中放置着不少障碍,要求出最大的不含障碍的矩形。2.分析:显然一个极大矩形是左右上下都被障碍挡住,无法再扩大的矩形,此时障碍也包括边界。3.方法:悬线法考虑以当前点所在行为下界,以往上能达到的最大距离为高度,正上方所有点的往左最大距离的最小值和往右......
  • 搜索算法合集 - By DijkstraPhoenix
    搜索算法合集ByDijkstraPhoenix深度优先搜索(DFS)引入如果现在有一个迷宫,如何走路径最短?方法走迷宫最简单粗暴的方法式什么呢?当然是把所有路都走一遍啦!如果是手动计算的话,可能会把你手指累得抽筋,但电脑不会,电脑具有强大的算力,这种暴力的事情当然是交给电脑做啦。深......
  • 算法 跑步问题 -- 暴力法
    目录跑步问题-暴力法题目分析规律代码实现1.初步框架2.dfs3.补全跑步问题-暴力法题目某人准备跑20圈来锻炼自己的身体,他准备分多次(>1)跑完,每次都跑正整数圈,然后休息下再继续跑。为了有效地提高自己的体能,他决定每次跑的圈数都必须比上次跑的多,设第一次圈数不能小于0......
  • 文心一言 VS 讯飞星火 VS chatgpt (362)-- 算法导论24.3 4题
    四、Gaedel教授写了一个程序,他声称该程序实现了Dijkstra算法。对于每个结点,该程序生成值和。请给出一个时间复杂度为的算法来检查教授所编写程序的输出。该算法应该判断每个结点的和属性是否与某棵最短路径树中的信息匹配。这里可以假设所有的边权重皆为非负值。如......