图解 React 的 diff 算法:核心就两个字 —— 复用

ecd7012cdf3c8889d67a7dc3f33699ee.gif

React 是基于 vdom 的前端框架,组件 render 产生 vdom,然后渲染器把 vdom 渲染出来。

state 更新的时候,组件会重新 render,产生新的 vdom,在浏览器平台下,为了减少 dom 的创建,React 会对两次的 render 结果做 diff,尽量复用 dom,提高性能。

diff 算法是前端框架中比较复杂的部分,代码比较多,但今天我们不上代码,只看图来理解它。

首先,我们先过一下 react 的 fiber 架构。

2139b5eab14da991508a47d31ec408a1.png

Fiber 架构

React 是通过 jsx 描述页面结构的:

function Profile() {return <div><img src="avatar.png" className="profile" /><h3>{[user.firstName, user.lastName].join(" ")}</h3></div>
}

经过 babel 等的编译会变成 render function:

import { jsx as _jsx } from "react/jsx-runtime";
import { jsxs as _jsxs } from "react/jsx-runtime";const profile = _jsxs("div", {children: [_jsx("img", {src: "avatar.png",className: "profile",}),_jsx("h3", {children: [user.firstName, user.lastName].join(" "),}),],
});

render function 执行结果就是 vdom,也就是 React Element 的实例:

532cdf51885bb9d4c901a01f56760066.png

在 16 之前,React 是直接递归渲染 vdom 的,setState 会触发重新渲染,对比渲染出的新旧 vdom,对差异部分进行 dom 操作。

在 16 之后,为了优化性能,会先把 vdom 转换成 fiber,也就是从树转换成链表,然后再渲染。整体渲染流程分成了两个阶段:

  • render 阶段:从 vdom 转换成 fiber,并且对需要 dom 操作的节点打上 effectTag 的标记

  • commit 阶段:对有 effectTag 标记的 fiber 节点进行 dom 操作,并执行所有的 effect 副作用函数。

从 vdom 转成 fiber 的过程叫做 reconcile(调和),这个过程是可以打断的,由 scheduler 调度执行。

4f5d3df7695cd843bb6adde2295f6bd1.png

diff 算法作用在 reconcile 阶段:

第一次渲染不需要 diff,直接 vdom 转 fiber。

再次渲染的时候,会产生新的 vdom,这时候要和之前的 fiber 做下对比,决定怎么产生新的 fiber,对可复用的节点打上修改的标记,剩余的旧节点打上删除标记,新节点打上新增标记。

接下来我们就来详细了解下 React 的 diff 算法。

d16a1b8eced806b5cb436d512ead06bd.png

React 的 diff 算法

在讲 diff 算法实现之前,我们要先想明白为什么要做 diff,不做行么?

当然可以,每一次渲染都直接把 vdom 转成 fiber 就行,不用和之前的做对比,这样是可行的。

其实 SSR 的时候就不用做 diff,因为会把组件渲染成字符串,第二次渲染也是产生字符串,难道这时候还要和之前的字符串对比下,有哪些字符串可以复用么?

不需要,SSR 的时候就没有 diff,每次都是 vdom 渲染出新的字符串。

那为什么浏览器里要做 diff 呢?

因为 dom 创建的性能成本很高,如果不做 dom 的复用,那前端框架的性能就太差了。

diff 算法的目的就是对比两次渲染结果,找到可复用的部分,然后剩下的该删除删除,该新增新增。

那具体怎么实现 React 的 diff 算法呢?

比如父节点下有 A、B、C、D 四个子节点,那渲染出的 vdom 就是这样的:

03ac696b1f69dfe65857ed01a043d528.png

经过 reconcile 之后,会变成这样的 fiber 结构:

1b9dda0630d9aa0095a3b543519cdb7a.png

那如果再次渲染的时候,渲染出了 A、C、B、E 的 vdom,这时候怎么处理呢?

12a03f0fe108e124af3818909e48f5d0.png再次渲染出 vdom 的时候,也要进行 vdom 转 fiber 的 reconcile 阶段,但是要尽量能复用之前的节点。

那怎么复用呢?

一一对比下不就行了?

先把之前的 fiber 节点放到一个 map 里,key 就是节点的 key:

77b531049019535c2b95b3d855b1f26a.png

然后每个新的 vdom 都去这个 map 里查找下有没有可以复用的,找到了的话就移动过来,打上更新的 effectTag:

9145148e9eb22f9135d593b2d2132615.png

这样遍历完 vdom 节点之后,map 里剩下一些,这些是不可复用的,那就删掉,打上删除的 effectTag;如果 vdom 中还有一些没找到复用节点的,就直接创建,打上新增的 effectTag。

这样就实现了更新时的 reconcile,也就是上面的 diff 算法。其实核心就是找到可复用的节点,剩下的旧节点删掉,新节点新增。

但有的时候可以再简化一下,比如上次渲染是 A、B、C、D,这次渲染也是 A、B、C、D,那直接顺序对比下就行,没必要建立 map 再找。

所以 React 的 diff 算法是分成两次遍历的:

第一轮遍历,一一对比 vdom 和老的 fiber,如果可以复用就处理下一个节点,否则就结束遍历。

如果所有的新的 vdom 处理完了,那就把剩下的老 fiber 节点删掉就行。

如果还有 vdom 没处理,那就进行第二次遍历:

第二轮遍历,把剩下的老 fiber 放到 map 里,遍历剩下的 vdom,从 map 里查找,如果找到了,就移动过来。

第二轮遍历完了之后,把剩余的老 fiber 删掉,剩余的 vdom 新增。

这样就完成了新的 fiber 结构的创建,也就是 reconcile 的过程。

比如上面那个例子,第一轮遍历就是这样的:

fe346f5b4a1a0cee35e07ade007f441e.png

一一对比新的 vdom 和 老的 fiber,发现 A 是可以复用的,那就创建新 fiber 节点,打上更新标记。

C 不可复用,所以结束第一轮遍历,进入第二轮遍历。

b618b918eb96bfbb266a8d12385b52e6.png

把剩下的 老 fiber 节点放到 map 里,然后遍历新的 vdom 节点,从 map 中能找到的话,就是可复用,移动过来打上更新的标记。

遍历完之后,剩下的老 fiber 节点删掉,剩下的新 vdom 新增。

这样就完成了更新时的 reconcile 的过程。

1787201e35f41bcd0deb465e94d43709.png

总结

react 是基于 vdom 的前端框架,组件渲染产生 vdom,渲染器把 vdom 渲染成 dom。

浏览器下使用 react-dom 的渲染器,会先把 vdom 转成 fiber,找到需要更新 dom 的部分,打上增删改的 effectTag 标记,这个过程叫做 reconcile,可以打断,由 scheducler 调度执行。reconcile 结束之后一次性根据 effectTag 更新 dom,叫做 commit。

这就是 react 的基于 fiber 的渲染流程,分成 render(reconcile + schedule)、commit 两个阶段。

当渲染完一次,产生了 fiber 之后,再次渲染的 vdom 要和之前的 fiber 对比下,再决定如何产生新的 fiber,目标是尽可能复用已有的 fiber 节点,这叫做 diff 算法。

react 的 diff 算法分为两个阶段:

第一个阶段一一对比,如果可以复用就下一个,不可以复用就结束。

第二个阶段把剩下的老 fiber 放到 map 里,遍历剩余的 vdom,一一查找 map 中是否有可复用的节点。

最后把剩下的老 fiber 删掉,剩下的新 vdom 新增。

这样就完成了更新时的 reconcile 过程。

其实 diff 算法的核心就是复用节点,通过一一对比也好,通过 map 查找也好,都是为了找到可复用的节点,移动过来。然后剩下的该删删该增增。

理解了如何找到可复用的节点,就理解了 diff 算法的核心。

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

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

相关文章

基于Confluent+Flink的实时数据分析最佳实践

简介&#xff1a;在实际业务使用中&#xff0c;需要经常实时做一些数据分析&#xff0c;包括实时PV和UV展示&#xff0c;实时销售数据&#xff0c;实时店铺UV以及实时推荐系统等&#xff0c;基于此类需求&#xff0c;Confluent实时计算Flink版是一个高效的方案。 业务背景 在…

深度解读「无影云电脑远程办公解决方案」

简介&#xff1a;疫情常态化&#xff0c;企业如何应对「远程」带来的挑战&#xff1f; 疫情之下&#xff0c;很多企业选择远程办公来保证业务的正常运营&#xff0c;而远程办公解决方案需要具备哪些技术能力来应对“远程”带来的挑战呢&#xff1f; 一&#xff0c;弹性伸缩能…

疯了?黑客公开“25美元入侵星链”法,SpaceX给他钱,还诚邀大家一起来“黑”?...

整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;近日&#xff0c;国外论坛 Reddit 上的一则热帖给人看“懵”了&#xff1a;SpaceX 诚邀大家来入侵自家的星链&#xff08;Starlink&#xff09;&#xff0c;成功者有赏。这令人不由感慨&#xff1a;居然…

车脉科技:业内首创“车企体验式营销”

随着新能源汽车不断得到人们的广泛关注&#xff0c;车企在新车型、新市场、新认知下如何提升销量以及用户如何选购一款合心意的智能电动车成为新能源智能时代的汽车营销难题。 车脉科技创业初衷 车脉科技的创始人孙泽锋说道&#xff1a;“创立车脉的初衷&#xff0c;我们一端想…

专访香侬科技:致力于让世界听到中文NLP的声音

像所有的创业者一样&#xff0c;香侬科技的初创团队胸怀梦想&#xff0c;期待有一天当人们提起香侬的时候&#xff0c;除了“信息论之父”&#xff0c;还能想起来有一家用技术在链接大千世界的科技公司——香侬科技。 新生的香侬科技选择“长在云上” 香侬科技的CTO王思宽说起…

驭数有道,天翼云数据库 TeleDB 全新升级

8月16日&#xff0c;以“红云天翼 安全普惠”为主题的天翼云TeleDB系列产品升级发布会在线上顺利举办。此次发布的天翼云自主研发云原生数据库进行了全新升级&#xff0c;推出一站式HTAP融合数据库&#xff0c;以及TeleDB数据库容灾双活方案&#xff0c;同时也展示了TeleDB数据…

如何构建一个流量无损的在线应用架构 | 专题尾篇

简介&#xff1a;我们将这些年在每一个环节中的相应解决方案&#xff0c;以产品化的方式沉淀到企业级分布式应用服务&#xff08;EDAS&#xff09;中。EDAS 致力于解决在线应用的全流程流量无损&#xff0c;经过 6 年的精细打磨&#xff0c;已经在流量接入与流量服务两个关键位…

云原生微服务技术趋势解读

简介&#xff1a;随着微服务技术门槛大幅下降&#xff0c;随着企业数字化升级步伐加速&#xff0c;随着云计算的迅速发展&#xff0c;微服务将无处不在&#xff1b;随着行业成熟度逐步提升&#xff0c;随着开源和标准推进&#xff0c;微服务的标准逐步形成&#xff0c;标准形成…

中国信通院魏博锴:云原生混部标准解读

嘉宾 | 魏博锴出品 | CSDN云原生2022年7月28日&#xff0c;中国信通院、腾讯云、FinOps产业标准工作组联合发起的《原动力x云原生正发声 降本增效大讲堂》系列直播活动第4讲如期举行&#xff0c;中国信通院云大所云计算部云原生研究员魏博锴解读了云原生混部标准。本文整理自魏…

从平凡到非凡 阿里云李克的技术进阶之路

简介&#xff1a;人物简介&#xff1a;李克 阿里云边缘云计算领域技术负责人 2009年硕士毕业加入阿里至今&#xff0c;一直从事CDN及边缘云领域的技术研发工作&#xff0c;在CDN、边缘计算等方向上有丰富的行业经验&#xff0c;全程参与了阿里云CDN商业化转型&#xff0c;边缘云…

一文搞懂redis

简介&#xff1a;NoSQL泛指非关系型数据库&#xff0c;随着web2.0互联网的诞生&#xff0c;传统的关系型数据库很难对付web2.0大数据时代&#xff01;尤其是超大规模的高并发的社区&#xff0c;暴露出来很多难以克服的问题&#xff0c;NoSQL在当今大数据环境下发展的十分迅速&a…

热搜!华为 30 岁以下员工仅占 28%,网友:35 岁危机呢?

整理 | 郑丽媛出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;一直以来&#xff0c;程序员的“35 岁”都是圈内的热议话题&#xff1a;35 岁是程序员的职业终结点、程序员到 35 岁就废了、超过 35 岁的程序员容易被裁……久而久之&#xff0c;35 岁逐渐变成了一个很…

阿里云发布业界首本《云计算公网质量白皮书》

随着互联网的发展&#xff0c;网络已经融入了整个社会发展的进程&#xff0c;如同血液贯通人类文明的五脏六腑。一旦网络出现故障&#xff0c;将给社会的政治、经济、文化造成重大损失。 2021年10月4日&#xff0c;Facebook在地球上”消失”了6小时&#xff0c;市值跌掉3000亿…

选轻量应用服务器or云服务器ECS?一图帮你彻底区分

简介&#xff1a;轻量应用服务器适合轻量级且访问量低的应用场景&#xff0c;更适合个人开发者、对新手小白更友好&#xff1b;而云服务器ECS可覆盖全业务场景&#xff08;如大数据分析&#xff0c;深度学习等&#xff09;&#xff0c;要求用户有一定的开发技术能力。 本文首发…

宜搭小技巧|一招摆脱纸质表单,数据收集更便捷

简介&#xff1a;开启「应用公开访问」&#xff0c;组织外成员也可提交数据。 许多公司在前台都会准备一个访客登记表&#xff0c;供来访者填写。但如果来访者数量较多&#xff0c;就会出现这样的问题…… 提供纸质表单供访客填写信息&#xff0c;使用起来繁琐且费时&#xff…

如何用 Serverless 低成本打造个人专属网盘?

简介&#xff1a;想要做个网盘不知如何开始&#xff0c;不妨花3分钟读读这篇&#xff0c;看看如何借助 Serverless &#xff0c;低成本的做一个“不限制网速、无限扩展、同时支持数百种文件格式在线预览、编辑、协作”的专属个人 & 家庭网盘~ 前言 随着全球大数据不断增长…

云之后,亚马逊云科技要为业界提供水和空气一样的安全防护

云巨头亚马逊云科技&#xff0c;正在持续加码云安全。 编辑 | 宋慧 出品 | CSDN云计算 提到亚马逊云科技&#xff0c;我们首先想到的是它在云领域的计算存储等技术和优势。不过亚马逊云科技却连续四年在举办它的全球安全大会 re:Inforce&#xff0c;刚刚 &#xff0c;2022 re:…

即学即会 Serverless | 如何解决 Serverless 应用开发部署的难题?

简介&#xff1a;开发者在选择使用 Serverless 时&#xff0c;仍会有开发和部署困难、厂商锁定等诸多担忧&#xff0c;有没有一种支持 Serverless 应用全生命周期管理的开发者工具&#xff0c;能够简单快速上手并真正帮助我们提升研发、运维的效能的呢&#xff1f; 破局&#x…

NBF事件中心架构设计与实现

简介&#xff1a;NBF是阿里巴巴供应链中台的基础技术团队打造的一个技术PaaS平台&#xff0c;她提供了微服务FaaS框架&#xff0c;低代码平台和中台基础设施等一系列的PaaS产品&#xff0c;旨在帮助业务伙伴快速复用和扩展中台能力&#xff0c;提升研发效能和对外的商业化输出。…

关于“算力”,这篇文章值得一看

作者 | 小枣君来源 | 鲜枣课堂今天这篇文章&#xff0c;我们来聊聊算力。这两年&#xff0c;算力可以说是ICT行业的一个热门概念。在新闻报道和大咖演讲中&#xff0c;总会出现它的身影。那么&#xff0c;究竟到底什么是算力&#xff1f;算力包括哪些类别&#xff0c;分别有什么…