尤大大教你Vue3.0虚拟Dom快速入门【实践】
ztj100 2024-11-02 14:31 25 浏览 0 评论
作者:蜗牛老湿
转发链接:https://juejin.im/post/5e9faa8fe51d4546fe263eda
整体尤大直播的过程,劝退大兄弟已经总结的贼棒了 ,请访问:
《聊聊昨晚尤雨溪现场针对Vue3.0 Beta版本新特性知识点汇总》
Vue3核心的Typescript,Proxy响应式,Composition解决代码反复横跳都有很棒的文章剖析了, 我总结一下虚拟Dom部分把,并对比一下React, vdom的重写也是vue3性能如此优秀的重要原因
Vue3.0的虚拟dom
先说结论,静态标记,upadte性能提升1.3~2倍,ssr提升2~3倍,怎么做到的呢
编译模板的静态标记
我们来看一段很常见的代码
<div id="app">
<h1>技术摸鱼</h1>
<p>今天天气真不错</p>
<div>{{name}}</div>
</div>
复制代码
vue2中会解析
function render() {
with(this) {
return _c('div', {
attrs: {
"id": "app"
}
}, [_c('h1', [_v("技术摸鱼")]), _c('p', [_v("今天天气真不错")]), _c('div', [_v(
_s(name))])])
}
}
复制代码
其中前面两个标签是完全静态的,后续的渲染中不会产生任何变化,Vue2中依然使用_c新建成vdom,在diff的时候需要对比,有一些额外的性能损耗
我们看下vue3中的解析结果
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1", null, "技术摸鱼"),
_createVNode("p", null, "今天天气真不错"),
_createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */)
]))
}
// Check the console for the AST
复制代码
最后一个_createVNode第四个参数1,只有带这个参数的,才会被真正的追踪,静态节点不需要遍历,这个就是vue3优秀性能的主要来源,再看复杂一点的
<div id="app">
<h1>技术摸鱼</h1>
<p>今天天气真不错</p>
<div>{{name}}</div>
<div :class="{red:isRed}">摸鱼符</div>
<button @click="handleClick">戳我</button>
<input type="text" v-model="name">
</div>
复制代码
解析的结果 在线预览
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1", null, "技术摸鱼"),
_createVNode("p", null, "今天天气真不错"),
_createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),
_createVNode("div", {
class: {red:_ctx.isRed}
}, "摸鱼符", 2 /* CLASS */),
_createVNode("button", { onClick: _ctx.handleClick }, "戳我", 8 /* PROPS */, ["onClick"])
]))
}
// Check the console for the AST
复制代码
_createVNode出第四个参数出现了别的数字,根据后面注释也很容易猜出,根据text,props等不同的标记,这样再diff的时候,只需要对比text或者props,不用再做无畏的props遍历, 优秀! 借鉴一下劝退大兄弟的注释
export const enum PatchFlags {
TEXT = 1,// 表示具有动态textContent的元素
CLASS = 1 << 1, // 表示有动态Class的元素
STYLE = 1 << 2, // 表示动态样式(静态如style="color: red",也会提升至动态)
PROPS = 1 << 3, // 表示具有非类/样式动态道具的元素。
FULL_PROPS = 1 << 4, // 表示带有动态键的道具的元素,与上面三种相斥
HYDRATE_EVENTS = 1 << 5, // 表示带有事件监听器的元素
STABLE_FRAGMENT = 1 << 6, // 表示其子顺序不变的片段(没懂)。
KEYED_FRAGMENT = 1 << 7, // 表示带有键控或部分键控子元素的片段。
UNKEYED_FRAGMENT = 1 << 8, // 表示带有无key绑定的片段
NEED_PATCH = 1 << 9, // 表示只需要非属性补丁的元素,例如ref或hooks
DYNAMIC_SLOTS = 1 << 10, // 表示具有动态插槽的元素
}
复制代码
如果同时有props和text的绑定呢, 位运算组合即可
<div id="app">
<h1>技术摸鱼</h1>
<p>今天天气真不错</p>
<div :id="userid"">{{name}}</div>
</div>
复制代码
import { createVNode as _createVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createBlock as _createBlock } from "vue"
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("h1", null, "技术摸鱼"),
_createVNode("p", null, "今天天气真不错"),
_createVNode("div", {
id: _ctx.userid,
"\"": ""
}, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
]))
}
// Check the console for the AST
复制代码
text是1,props是8,组合在一起就是9,我们可以简单的通过位运算来判定需要做text和props的判断, 按位与即可,只要不是0就是需要比较
位运算来做类型组合 本身就是一个最佳实践,react大兄弟也是一样的 代码
export const PLUGIN_EVENT_SYSTEM = 1;
export const RESPONDER_EVENT_SYSTEM = 1 << 1;
export const USE_EVENT_SYSTEM = 1 << 2;
export const IS_TARGET_PHASE_ONLY = 1 << 3;
export const IS_PASSIVE = 1 << 4;
export const PASSIVE_NOT_SUPPORTED = 1 << 5;
export const IS_REPLAYED = 1 << 6;
export const IS_FIRST_ANCESTOR = 1 << 7;
export const LEGACY_FB_SUPPORT = 1 << 8;
复制代码
事件缓存
绑定的@click会存在缓存里 链接
<div id="app">
<button @click="handleClick">戳我</button>
</div>
复制代码
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", { id: "app" }, [
_createVNode("button", {
onClick: _cache[1] || (_cache[1] = $event => (_ctx.handleClick($event)))
}, "戳我")
]))
}
复制代码
传入的事件会自动生成并缓存一个内联函数再cache里,变为一个静态节点。这样就算我们自己写内联函数,也不会导致多余的重复渲染 真是优秀啊
静态提升
代码
<div id="app">
<h1>技术摸鱼</h1>
<p>今天天气真不错</p>
<div>{{name}}</div>
<div :class="{red:isRed}">摸鱼符</div>
</div>
复制代码
const _hoisted_1 = { id: "app" }
const _hoisted_2 = _createVNode("h1", null, "技术摸鱼", -1 /* HOISTED */)
const _hoisted_3 = _createVNode("p", null, "今天天气真不错", -1 /* HOISTED */)
export function render(_ctx, _cache) {
return (_openBlock(), _createBlock("div", _hoisted_1, [
_hoisted_2,
_hoisted_3,
_createVNode("div", null, _toDisplayString(_ctx.name), 1 /* TEXT */),
_createVNode("div", {
class: {red:_ctx.isRed}
}, "摸鱼符", 2 /* CLASS */)
]))
}
复制代码
vue3和react fiber的vdom
很多人吐槽越来越像React,其实越来越像的api,代表着前端的两个方向
Vue1.x
没有vdom,完全的响应式,每个数据变化,都通过响应式通知机制来新建Watcher干活,就像独立团规模小的时候,每个战士入伍和升职,都主动通知咱老李,管理方便
项目规模变大后,过多的Watcher,会导致性能的瓶颈
React15x
而React15时代,没有响应式,数据变了,整个新数据和老的数据做diff,算出差异 就知道怎么去修改dom了,就像老李指挥室有一个模型,每次人事变更,通过对比所有人前后差异,就知道了变化, 看起来有很多计算量,但是这种immutable的数据结构对大型项目比较友好,而且Vdom抽象成功后,换成别的平台render成为了可能,无论是打鬼子还是打国军,都用一个vdom模式
碰到的问题一样,如果dom节点持续变多,每次diff的时间超过了16ms,就可能会造成卡顿(60fps)
Vue2.x
引入vdom,控制了颗粒度,组件层面走watcher通知, 组件内部走vdom做diff,既不会有太多watcher,也不会让vdom的规模过大,diff超过16ms,真是优秀啊 就像独立团大了以后,只有营长排长级别的变动,才会通知老李,内部的自己diff管理了
React 16 Fiber
React走了另外一条路,既然主要问题是diff导致卡顿,于是React走了类似cpu调度的逻辑,把vdom这棵树,微观变成了链表,利用浏览器的空闲时间来做diff,如果超过了16ms,有动画或者用户交互的任务,就把主进程控制权还给浏览器,等空闲了继续,特别像等待女神的备胎
diff的逻辑,变成了单向的链表,任何时候主线程女神有空了,我们在继续蹭上去接盘做diff,大家研究下requestIdleCallback就知道,从浏览器角度看 是这样的
大概代码
requestIdelCallback(myNonEssentialWork);
// 等待女神空闲
function myNonEssentialWork (deadline) {
// deadline.timeRemaining()>0 主线程女神还有事件
// 还有diff任务没算玩
while (deadline.timeRemaining() > 0 && tasks.length > 0) {
doWorkIfNeeded();
}
// 女神没时间了,把女神还回去
if (tasks.length > 0){
requestIdleCallback(myNonEssentialWork);
}
}
复制代码
Vue3
这里的静态提升和事件缓存刚才说过了,就不说了,其实我也很纳闷,这些静态标记和事件缓存,React本身也可以做,为啥就不实现了,连shouldComponentUpdate都得自己定义,为啥不把默认的组件都变成pure或者memo呢,唉,也许这就是人生把
React给你自由,Vue让你持久,可能也是现在国内Vue和React都如此受欢迎的原因把
Vue3通过Proxy响应式+组件内部vdom+静态标记,把任务颗粒度控制的足够细致,所以也不太需要time-slice了
人生啊,小孩才天天研究利弊, 成年人选择我都要,也期待React17的新特性
直播小细节
最后提问期间,强如尤大,也没法回避发量的问题,可惜没推荐啥护发素,我仔细看了一下,好像vue3发布后,尤大发际线确实提升了 囧 祝大家技术提升的同时也能有乌黑的秀发
作者:蜗牛老湿
转发链接:https://juejin.im/post/5e9faa8fe51d4546fe263eda
相关推荐
- 离谱!写了5年Vue,还不会自动化测试?
-
前言大家好,我是倔强青铜三。是一名热情的软件工程师,我热衷于分享和传播IT技术,致力于通过我的知识和技能推动技术交流与创新,欢迎关注我,微信公众号:倔强青铜三。Playwright是一个功能强大的端到...
- package.json 与 package-lock.json 的关系
-
模块化开发在前端越来越流行,使用node和npm可以很方便的下载管理项目所需的依赖模块。package.json用来描述项目及项目所依赖的模块信息。那package-lock.json和...
- Github 标星35k 的 SpringBoot整合acvtiviti开源分享,看完献上膝盖
-
前言activiti是目前比较流行的工作流框架,但是activiti学起来还是费劲,还是有点难度的,如何整合在线编辑器,如何和业务表单绑定,如何和系统权限绑定,这些问题都是要考虑到的,不是说纯粹的把a...
- Vue3 + TypeScript 前端研发模板仓库
-
我们把这个Vue3+TypeScript前端研发模板仓库的初始化脚本一次性补全到可直接运行的状态,包括:完整的目录结构所有配置文件研发规范文档示例功能模块(ExampleFeature)...
- Vue 2迁移Vue 3:从响应式到性能优化
-
小伙伴们注意啦!Vue2已经在2023年底正式停止维护,再不升级就要面临安全漏洞没人管的风险啦!而且Vue3带来的性能提升可不是一点点——渲染速度快40%,内存占用少一半,更新速度直接翻倍!还在...
- VUE学习笔记:声明式渲染详解,对比WEB与VUE
-
声明式渲染是指使用简洁的模板语法,声明式的方式将数据渲染进DOM系统。声明式是相对于编程式而言,声明式是面向对象的,告诉框架做什么,具体操作由框架完成。编程式是面向过程思想,需要手动编写代码完成具...
- 苏州web前端培训班, 苏州哪里有web前端工程师培训
-
前端+HTML5德学习内容:第一阶段:前端页面重构:PC端网站布局、HTML5+CSS3基础项目、WebAPP页面布局;第二阶段:高级程序设计:原生交互功能开发、面向对象开发与ES5/ES6、工具库...
- 跟我一起开发微信小程序——扩展组件的代码提示补全
-
用户自定义代码块步骤:1.HBuilderX中工具栏:工具-代码块设置-vue代码块2.通过“1”步骤打开设置文件...
- JimuReport 积木报表 v1.9.3发布,免费可视化报表
-
项目介绍积木报表JimuReport,是一款免费的数据可视化报表,含报表、大屏和仪表盘,像搭建积木一样完全在线设计!功能涵盖:数据报表、打印设计、图表报表、门户设计、大屏设计等!...
- 软开企服开源的无忧企业文档(V2.1.3)产品说明书
-
目录1....
- 一款面向 AI 的下一代富文本编辑器,已开源
-
简介AiEditor是一个面向AI的下一代富文本编辑器。开箱即用、支持所有前端框架、支持Markdown书写模式什么是AiEditor?AiEditor是一个面向AI的下一代富文本编辑...
- 玩转Markdown(2)——抽象语法树的提取与操纵
-
上一篇玩转Markdown——数据的分离存储与组件的原生渲染发布,转眼已经鸽了大半年了。最近在操纵mdast生成md文件的时候,心血来潮,把玩转Markdown(2)给补上了。...
- DeepseekR1+ollama+dify1.0.0搭建企业/个人知识库(入门避坑版)
-
找了网上的视频和相关文档看了之后,可能由于版本不对或文档格式不对,很容易走弯路,看完这一章,可以让你少踩三天的坑。步骤和注意事项我一一列出来:1,前提条件是在你的电脑上已配置好ollama,dify1...
- 升级JDK17的理由,核心是降低GC时间
-
升级前后对比升级方法...
- 一个vsCode格式化插件_vscode格式化插件缩进量
-
ESlint...
你 发表评论:
欢迎- 一周热门
-
-
MySQL中这14个小玩意,让人眼前一亮!
-
旗舰机新标杆 OPPO Find X2系列正式发布 售价5499元起
-
【VueTorrent】一款吊炸天的qBittorrent主题,人人都可用
-
面试官:使用int类型做加减操作,是线程安全吗
-
C++编程知识:ToString()字符串转换你用正确了吗?
-
【Spring Boot】WebSocket 的 6 种集成方式
-
PyTorch 深度学习实战(26):多目标强化学习Multi-Objective RL
-
pytorch中的 scatter_()函数使用和详解
-
与 Java 17 相比,Java 21 究竟有多快?
-
基于TensorRT_LLM的大模型推理加速与OpenAI兼容服务优化
-
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)
- vmware17pro最新密钥 (34)
- mysql单表最大数据量 (35)