虚拟dom?diff算法?key?Vue原理的核心三问?打包教你搞定。
为什么需要虚拟DOM
先介绍浏览器加载一个HTML文件需要做哪些事,帮助我们理解为什么我们需要虚拟DOM。webkit引擎的处理流程,如下图所示:

所有浏览器的引擎工作流程都差不多,如上图大致分5步:
第一步,用HTML分析器,分析HTML元素,构建一颗DOM树。
第二步:用CSS分析器,分析CSS文件和元素上的inline样式,生成页面的样式表。
第三步:将上面的DOM树和样式表,关联起来,构建一颗Render树。这一过程又称为Attachment。每个DOM节点都有attach方法,接受样式信息,返回一个render对象(又名renderer)。这些render对象最终会被构建成一颗Render树。
第四步:有了Render树后,浏览器开始布局,会为每个Render树上的节点确定一个在显示屏上出现的精确坐标值。
第五步:Render数有了,节点显示的位置坐标也有了,最后就是调用每个节点的paint方法,让它们显示出来。
当你用传统的源生api或jQuery去操作DOM时,浏览器会从构建DOM树开始从头到尾执行一遍流程。比如当你在一次操作时,需要更新10个DOM节点,理想状态是一次性构建完DOM树,再执行后续操作。但浏览器没这么智能,收到第一个更新DOM请求后,并不知道后续还有9次更新操作,因此会马上执行流程,最终执行10次流程。显然例如计算DOM节点的坐标值等都是白白浪费性能,可能这次计算完,紧接着的下一个DOM更新请求,这个节点的坐标值就变了,前面的一次计算是无用功。
即使计算机硬件一直在更新迭代,操作DOM的代价仍旧是昂贵的,频繁操作还是会出现页面卡顿,影响用户的体验。真实的DOM节点,哪怕一个最简单的div也包含着很多属性,可以打印出来直观感受一下:

实现虚拟DOM
我们来实现一个虚拟DOM。例如一个真实的DOM节点:

用js对象模拟DOM节点的好处是,页面的更新可以先全部反映在js对象上,操作内存中的js对象的速度显然要快多了。等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制。
那具体怎么实现呢?看一下Element方法的具体实现:

第一个参数是节点名(如div),第二个参数是节点的属性(如class),第三个参数是子节点(如ul的li)。除了这三个参数会被保存在对象上外,还保存了key和count。

有了js对象后,最终还需要将其映射成真实的DOM:

Diff算法
我们已经完成了创建虚拟DOM并将其映射成真实DOM的工作,这样所有的更新都可以先反映到虚拟DOM上,如何反映呢?需要明确一下Diff算法。
两棵树如果完全比较时间复杂度是O(n^3),但参照《深入浅出React和Redux》一书中的介绍,React的Diff算法的时间复杂度是O(n)。要实现这么低的时间复杂度,意味着只能平层地比较两棵树的节点,放弃了深度遍历。这样做,似乎牺牲了一定的精确性来换取速度,但考虑到现实中前端页面通常也不会跨层级移动DOM元素,所以这样做是最优的。我们新创建一棵树,用于和之前的树进行比较:

只考虑平层的Diff算法,就简单多了,只需要考虑以下4种情况:
第一种是最简单的,节点类型变了,例如下图中的P变成了h3。我们将这个过程称之为REPLACE。直接将旧节点卸载(componentWillUnmount)并装载新节点(componentWillMount)就行了。

(为简单起见上图隐藏了文本节点)旧节点包括下面的子节点都将被卸载,如果新节点和旧节点仅仅是类型不同,但下面的所有子节点都一样时,这样做显得效率不高。但为了避免O(n^3)的时间复杂度,这样做是值得的。这也提醒了开发者,应该避免无谓的节点类型的变化,例如运行时将div变成p就没什么太大意义。
第二种也比较简单,节点类型一样,仅仅属性或属性值变了。
第三种是文本变了,文本对也是一个Text Node,也比较简单,直接修改文字内容就行了,我们将这个过程称之为TEXT。
第四种是移动,增加,删除子节点,我们将这个过程称之为REORDER。例如:

在中间插入一个节点,程序员写代码很简单:$(B).after(F)。但如何高效地插入呢?简单粗暴的做法是:卸载C,装载F,卸载D,装载C,卸载E,装载D,装载E。如下图:



所以一句话,key的作用主要是为了高效的更新虚拟DOM。另外Vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让Vue可以区分它们,否则Vue只会替换其内部属性而不会触发过渡效果。

映射成真实DOM
虚拟DOM有了,Diff也有了,现在就可以将Diff应用到真实DOM上了。深度遍历DOM将Diff的内容更新进去,其实就是根据Diff信息调用源生API操作DOM,虚拟DOM的目的是将所有操作累加起来,统计计算出所有的变化后,统一更新一次DOM。其实即使不懂原理,业务代码照样写,但理解原理后,出了什么新东东如React Fiber才能快速跟上。前端就是这样痛并快乐着。
虚拟dom?diff算法?key?Vue原理的核心三问?打包教你搞定。的更多相关文章
- 图解vue中 v-for 的 :key 的作用,虚拟dom Diff算法
其实不只是vue,react中在执行列表渲染时也会要求给每个组件添加上key这个属性. 要解释key的作用,不得不先介绍一下虚拟DOM的Diff算法了. 我们知道,vue和react都实现了一套虚拟D ...
- react虚拟dom diff算法
react虚拟dom:依据diff算法 前端:更新状态.更新视图:所以前端页面的性能问题主要是由Dom操作引起的,解放Dom操作复杂性 刻不容缓 因为:Dom渲染慢,而JS解析编译相对非常非常非常快! ...
- 深入Vue2.x的虚拟DOM diff原理
一.前言 Vue的核心是双向绑定和虚拟DOM(下文我们简称为vdom),关于双向绑定可以参阅木琴的文章<剖析Vue原理&实现双向绑定MVVM>,vdom是树状结构,其节点为vnod ...
- 最近发现了一篇讲解Vue的虚拟DOM,diff很棒的文章,特定记录转载一下
本文章是转载的,为了方便以后复习,特地记录一下.他人请去原地址观看!!! 文章原地址:https://blog.csdn.net/m6i37jk/article/details/78140159 作者 ...
- 谈谈Vue/React中的虚拟DOM(vDOM)与Key值
谈谈Vue/React中的虚拟DOM(vDOM)与Key值 一.DocumentFragment 在了解虚拟DOM前,先来了解DOM的一个对象属性--DocumentFragment. 在一次操作中, ...
- 虚拟DOM与DOM diff算法
虚拟DOM是什么? 一个虚拟DOM(元素)是一个一般的js对象, 准确的说是一个对象树(倒立的) 虚拟DOM保存了真实DOM的层次关系和一些基本属性,与真实DOM一一对应,如果只是更新虚拟DOM, 页 ...
- 2021升级版微服务教程6—Ribbon使用+原理+整合Nacos权重+实战优化 一篇搞定
2021升级版SpringCloud教程从入门到实战精通「H版&alibaba&链路追踪&日志&事务&锁」 教程全目录「含视频」:https://gitee.c ...
- 16_虚拟dom和dom diff算法
虚拟dom的作用:是为了减少操作真实的dom 初始化显示界面的过程: 1.创建虚拟dom树——>真实dom树——>绘制页面显示 更新界面的过程: 2.绘制页面显示——>setStat ...
- react 局部更新的关键算法 DOM diff算法
下图是diff算法结构的详细解析: 要点总结:DIFF算法在执行时有三个维度,分别是Tree DIFF.Component DIFF和Element DIFF,执行时按顺序依次执行,它们的差异仅仅因为 ...
随机推荐
- Raspberry pi 3b+ 安装dotnet5 VSCode Remote-SSH 远程开发
前言 VSCode 安装Remote-SSH 配置好树莓派 VSCode 自带SSH控制台 终端输入命令 下载&安装 net5 下载wget https://dotnetcli.azureed ...
- 【C#】C#中使用GDAL3(一):Windows下超详细编译C#版GDAL3.3.0(VS2015+.NET 4+32位/64位)
转载请注明原文地址:https://www.cnblogs.com/litou/p/15004877.html 目录 一.介绍 二.编译准备 三.编译SQLite 四.编译LibTiff 五.编译PR ...
- FormData提交文件(十四)
问题 在通过ajax提交表单时,表单中有Excel文件,在后台还需要读取excel文件中的数据,普通的提交方式无法实现.可以通过创建FormData对象的方式. 代码示例: 前端: 创建想要提交的fo ...
- node fs-extra文件操作模块的使用(支持同步、异步)
用法参见:fs-extra
- 第一篇 -- 安装和配置PyQt5
我的电脑环境是:Win10 + Python3.6.4 + JetBrains PyCharm 2017.3.2 x64 之前用tkinter写界面,现在学习如何用PyQt5写界面. 安装PyQt5: ...
- MetaBase使用iframe内嵌到Vue页面样式优化
Matebase是一个开源,易上手的BI工具,这里不做太多介绍了. 官网地址:https://www.metabase.com/ 解决问题描述: 使用iframe内嵌Metabase公开链接之后,页面 ...
- 根据随身固态U盘卷标搜索U盘盘符并打开文件的批处理脚本.bat 徐晓亮 595076941@qq.com 2019年12月19日6点50分
@Echo offRem 根据随身固态U盘卷标搜索U盘盘符并打开文件的批处理脚本.batRem 徐晓亮 595076941@qq.com 2019年12月19日6点50分 Rem 此批处理脚本源代码的 ...
- 「必知必会」最细致的 ArrayList 原理分析
从今天开始也正式开 JDK 原理分析的坑了,其实写源码分析的目的不再是像以前一样搞懂原理,更重要的是看看他们编码风格更进一步体会到他们的设计思想.看源码前先自己实现一个再比对也许会有不一样的收获! ...
- Hybrid接口
目录 一.Hybrid接口 1.1 VLan的基本概念 1.2 Hybrid接口特点 1.3 Hybrid接口工作原理 1.4 Hybrid配置 一.Hybrid接口 1.1 VLan的基本概念 特点 ...
- Jenkins自动化部署最完整教程
1.概述 Jenkins 是一个可扩展的持续集成引擎.主要用于持续.自动地构建/测试软件项目.监控一些定时执行的任务.Jenkins用Java语言编写,可在Tomcat等流行的servlet容器中运行 ...