人云亦云,并不会让你变得有多优秀,而会让你越来越随大流。

当你和别的开发在聊到 Vue 3.0 版本发布,有哪些亮点时,你的答案之一肯定有“它变得更快了,性能上快了 1.2 ~ 2倍”。

那么我就想问你,是什么让 Vue 变快了,尤大已经在 beta 版的线上直播上告诉了我们答案。

PatchFlag(静态标记)

Vue 2.x 中的虚拟 DOM 是全量对比的模式,而到了 Vue 3.0 开始,新增了静态标记(PatchFlag)。

在更新前的节点进行对比的时候,只会去对比带有静态标记的节点。并且 PatchFlag 枚举定义了十几种类型,用以更精确的定位需要对比节点的类型。下面我们通过图文实例分析这个对比的过程。

假设我们有下面一段代码:

<div>
<p>老八食堂</p>
<p>{{ message }}</p>
</div>

在 Vue 2.x 的全量对比模式下,如下图所示:

通过上图,我们发现,Vue 2.x 的 diff 算法将每个标签都比较了一次,最后发现带有 {{ message }} 变量的标签是需要被更新的标签,显然这还有优化的空间。

在 Vue 3.0 中,对 diff 算法进行了优化,在创建虚拟 DOM 时,根据 DOM 内容是否会发生变化,而给予相对应类型的静态标记(PatchFlag),如下图所示:

观察上图,不难发现试图的更新只对带有 flag 标记的标签进行了对比(diff),所以只进行了 1 次比较,而相同情况下,Vue 2.x 则进行了 3 次比较。这便是 Vue 3.0 比 Vue2.x 性能好的第一个原因。

我们再通过把模板代码转译成虚拟 DOM,来验证我们上述的分析是否正确。我们可以打开模板转化网站,对上述代码进行转译:

上图蓝色框内为转译后的虚拟 DOM 节点,第一个 P 标签为写死的静态文字,而第二个 P 标签则为绑定的变量,所以打上了 1 标签,代表的是 TEXT(文字),标记枚举类型如下:

export const enum PatchFlags {

  TEXT = 1,// 动态的文本节点
CLASS = 1 << 1, // 2 动态的 class
STYLE = 1 << 2, // 4 动态的 style
PROPS = 1 << 3, // 8 动态属性,不包括类名和样式
FULL_PROPS = 1 << 4, // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
HYDRATE_EVENTS = 1 << 5, // 32 表示带有事件监听器的节点
STABLE_FRAGMENT = 1 << 6, // 64 一个不会改变子节点顺序的 Fragment
KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
NEED_PATCH = 1 << 9, // 512
DYNAMIC_SLOTS = 1 << 10, // 动态 solt
HOISTED = -1, // 特殊标志是负整数表示永远不会用作 diff
BAIL = -2 // 一个特殊的标志,指代差异算法
}

hoistStatic(静态提升)

我们平时在开发过程中写函数的时候,定义一些写死的变量时,都会将变量提升出去定义,如下所示:

const PAGE_SIZE = 10
function getData () {
$.get('/data', {
data: {
page: PAGE_SIZE
},
...
})
}

诸如上述代码,如果将 PAGE_SIZE = 10 写在 getData 方法内,每次调用 getData 都会重新定义一次变量。

Vue 3.0 在这方面也做了同样的优化,继续用我们上一个例子写的代码,观察编译之后的虚拟 DOM 结构,如下所示:

没有做静态提升前:

选择 Option 下的 hoistStatic

静态提升后:

细心的同学会发现, 老八食堂 被提到了 render 函数外,每次渲染的时候只要取 _hoisted_1 变量便可。认真看文章的同学又会发现一个细节, _hoisted_1 被打上了 PatchFlag ,静态标记值为 -1 ,特殊标志是负整数表示永远不会用作 Diff。也就是说被打上 -1 标记的,将不在参与 Diff 算法,这又提升了 Vue 的性能。

cacheHandler(事件监听缓存)

默认情况下 @click 事件被认为是动态变量,所以每次更新视图的时候都会追踪它的变化。但是正常情况下,我们的 @click 事件在视图渲染前和渲染后,都是同一个事件,基本上不需要去追踪它的变化,所以 Vue 3.0 对此作出了相应的优化叫事件监听缓存,我们在上述代码中加一段:

<div>
<p @click="handleClick">屋里一giao</p>
</div>

编译后如下图所示(还未开启 cacheHandler):

在未开启事件监听缓存的情况下,我们看到这串代码编译后被静态标记为 8,之前讲解过被静态标记的标签就会被拉去做比较,而静态标记 8 对应的是“动态属性,不包括类名和样式”。 @click 被认为是动态属性,所以我们需要开启 Options 下的 cacheHandler 属性,如下图所示:

细心的同学又会发现,开启 cacheHandler 之后,编译后的代码已经没有静态标记(PatchFlag),也就表明图中 P 标签不再被追踪比较变化,进而提升了 Vue 的性能。

SSR 服务端渲染

当你在开发中使用 SSR 开发时,Vue 3.0 会将静态标签直接转化为文本,相比 React 先将 jsx 转化为虚拟 DOM,再将虚拟 DOM 转化为 HTML,Vue 3.0 已经赢了。

StaticNode(静态节点)

上述 SSR 服务端渲染,会将静态标签直接转化为文本。在客户端渲染的时候,只要标签嵌套得足够多,编译时也会将其转化为 HTML 字符串,如下图所示:

需要开启 Options 下的 hoistStatic

总结

以上便是 Vue3.0 在编译时针对虚拟 DOM 的性能优化,这使得 Vue 3.0 在性能上是 Vue 2.x 的 1.2~2倍。

创建了一个 Vue3 的学习仓库 vue3-examples,仓库地址:https://github.com/newbee-ltd/vue3-examples,此仓库将不定期更新各种 Vue3.0 相关的知识及各种整合 Demo 及 Vue3 使用小技巧,大家可以关注一下,有什么建议也欢迎大家给我留言。

除注明转载/出处外,皆为作者原创,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。

Vue3教程:Vue 3.x 快在哪里?的更多相关文章

  1. Vue3教程:Vue 3 + Element Plus + Vite 2 的后台管理系统开源啦

    之前发布过一篇文章<Vue3教程:开发一个 Vue 3 + element-plus 的后台管理系统>,文中提到会开发并开源一个 Vue 3 + Element Plus 的项目供大家练手 ...

  2. 助你上手Vue3全家桶之Vue3教程

    目录 前言 1,setup 1.1,返回值 1.2,注意点 1.3,语法 1.4,setup的参数 2,ref 创建响应式数据 3,reactive 创建响应式数据 4,computed 计算属性 5 ...

  3. 【强烈推荐,超详细,实操零失误】node.js安装 + npm安装教程 + Vue开发环境搭建

    node.js安装 + npm安装教程 + Vue开发环境搭建 [强烈推荐,超详细,实操零失误] 原博客园地址:https://www.cnblogs.com/goldlong/p/8027997.h ...

  4. vue2升级vue3:Vue Demij打通vue2与vue3壁垒,构建通用组件

    如果你的vue2代码之前是使用vue-class-component 类组件模式写的.选择可以使用 https://github.com/facing-dev/vue-facing-decorator ...

  5. Vue3教程:一个基于 Vue 3 + Vant 3 的商城项目开源啦!

    之前发布过一篇文章,告诉大家我要开发一个 Vue3 的商城项目并开源到 GitHub 上,供大家练手和学习,随后也一直有收到留言和反馈,问我开发到哪里了,什么时候开源之类的问题,今天终于可以通知大家, ...

  6. 【vue】vue.js安装教程/vue项目搭建

    前提:已安装nodejs——npm  (备注教程  “物理安装”  ) 第一步:建了一个managerSys文件夹,用于保存项目 第二步:从cmd进入该文件夹,之后开始安装vue.js相关 1)在该项 ...

  7. Vue3.0是如何变快的

    1.diff算法优化 + Vue2中的虚拟dom是进行全量的对比 https://vue-next-template-explorer.netlify.app/ + Vue3新增了静态标记(Patch ...

  8. Vue3教程:用 Vue3 开发小程序,这里有一份实际的代码案例!

    前言 寻寻觅觅冷冷清清,凄凄惨惨戚戚. Vue 3 发布以后,最近也在学习和写一些 Vue3 的 demo 和项目,我也一直想着什么时候能在小程序里使用新特性? 于是我翻遍了市面上的小程序框架,如 u ...

  9. [js高手之路] vue系列教程 - vue的事件绑定与方法(2)

    一.在vue中,绑定事件,用v-on:事件类型, 如绑定一个点击事件, 我们可以这样子做 window.onload = function () { var c = new Vue({ el : 'b ...

随机推荐

  1. input 与 button 的问题 (空隙/不等高/对不齐)及 解决办法

    1. input 与 button 为什么有空隙? - 要明白为什么,需要了解一下几点基础知识(耐心看完,你会发现竟如此简单)     1. input 与 button 都属于行级块元素,都具有文本 ...

  2. vgg学习

    LeNet-5是一个较简单的卷积神经网络.下图显示了其结构:输入的二维图像,先经过两次卷积层到池化层,再经过全连接层,最后使用softmax分类作为输出层. AlexNet中包含了几个比较新的技术点, ...

  3. 常用简单电脑bai快捷键大全

    Ctrl+C 复制.duCtrl+X 剪切.Ctrl+V粘贴.Ctrl+Z撤销.Ctrl+A全选所有文件.zhiDelete删除.daoShift+Delete避开回收站直接永久删除(不可找回).F3 ...

  4. 激情的来源 Imagine how much you love it !

    激情来自哪里?我想可能我找到了,精髓就在那个标题! 想象你有多么爱它!你就会爱上他,想象你有多么喜欢某一个东西,你很有可能就喜欢上他,着手去了解他,接触他. 如果带着这种想象状态的激情,工作和学习会有 ...

  5. fork函数拓展

    1.fork之后父子进程共享文件:文件引用计数的值改变,共享偏移. 在下面的例子中test.txt为parentchil.如果子进程没有睡眠,两个进程交叉执行,内容不可预测. 1 #include&l ...

  6. psycopg2模块安装问题

    我的平台是win10(x64).python3.7,打算通过psycopg2模块来操作Greenplum数据库,我通过pip install psycopg2 安装了psycopg2模块,也提示安装成 ...

  7. linux修改网卡的mac地址

    linux在安装一些软件的时候可能会用到修改主机的mac地址的问题,在网卡配置文件 /etc/network/interface 中添加mac地址的方式我在修改重启机器后没有生效,所以采用其他方式 在 ...

  8. win10,ubuntu时间不对问题

    sudo apt-get install ntpdate sudo ntpdate time.windows.com   # ntp2.aliyun.com      然后将时间更新到硬件上: sud ...

  9. 采集post传输的数据

    采集数据,网页上的数据是开发者通过ajax的post方式显示的,就得用到curl以及它的跨域方法 代码: $post_data------post传过去的参数 $ch = curl_init(); $ ...

  10. 精尽MyBatis源码分析 - 插件机制

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...