vue3【详解】 vue3 比 vue2 快的原因

ops/2025/2/22 16:02:06/

使用 Proxy 实现响应式

vue3使用的 Proxy 在处理属性的读取和写入时,比vue2使用的defineProperty 有更好的性能(速度加倍的同时,内存还能减半!)

更新类型标记 Patch Flag

在编译模板时(将vue语法转换为js描述的虚拟节点vdom), vue3 对动态节点添加了标记,效果如下:

  • 静态节点无标记
<!-- 静态节点 -->
<span>你好</span>

编译后

_createElementVNode("span", null, "你好")
  • 动态文本节点会标记为1/*TEXT*/
<span>{{msg}}</span>

编译后

_createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)

更多vue3模板编译效果可通过下方网站预览
https://template-explorer.vuejs.org/

有了这些动态节点标记,vue3 在diff 算法时便可以跳过对不会发生变化的静态节点的比较,只比较可能发生变化的动态节点,从而提升了 diff 算法的性能,比需要比较静态节点的 vue2 更快!

在这里插入图片描述

缓存静态节点 hoistStatic

是一种典型的拿空间换时间的优化策略,具体操作如下:

  • 将静态节点的定义,提升到父作用域,缓存起来(缓存后,就能在之后的编译中跳过编译,从而提升编译速度!)
<span>你好</span>
<span>{{msg}}</span>

编译后

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"const _hoisted_1 = /*#__PURE__*/_createElementVNode("span", null, "你好", -1 /* HOISTED */)export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock(_Fragment, null, [_hoisted_1,_createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)], 64 /* STABLE_FRAGMENT */))
}

可见静态节点被定义为 _hoisted_1 提升到了父作用域,进行了缓存

  • 对超过9个的相邻静态节点进行合并(合并后,优化了代码结构,减小了编译后代码的体积,实现了编译速度的提升!)
<span>你好1</span>
<span>你好2</span>
<span>你好3</span>
<span>你好4</span>
<span>你好5</span>
<span>你好6</span>
<span>你好7</span>
<span>你好8</span>
<span>你好9</span>
<span>你好10</span>

编译后

import { createElementVNode as _createElementVNode, createStaticVNode as _createStaticVNode } from "vue"const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<span>你好1</span><span>你好2</span><span>你好3</span><span>你好4</span><span>你好5</span><span>你好6</span><span>你好7</span><span>你好8</span><span>你好9</span><span>你好10</span>", 10)export function render(_ctx, _cache, $props, $setup, $data, $options) {return _hoisted_1
}

缓存事件 cacheHandler

也是一种典型的拿空间换时间的优化策略,具体操作如下:

  • 给事件添加缓存(在之后的编译中跳过编译,提升编译速度!)
<button @click='save'>保存</button>

编译后

import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock("button", {onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.save && _ctx.save(...args)))}, "保存"))
}

_cache[0] || (_cache[0] = ... 的部分,可见使用了缓存(已有缓存,则使用缓存,若无缓存,则重新编译)

SSR 优化

静态节点直接输出,绕过了 vdom

<span>你好</span>
<span>{{msg}}</span>

编译后

import { ssrRenderAttrs as _ssrRenderAttrs, ssrInterpolate as _ssrInterpolate } from "vue/server-renderer"export function ssrRender(_ctx, _push, _parent, _attrs, $props, $setup, $data, $options) {const _cssVars = { style: { color: _ctx.color }}_push(`<!--[--><span${_ssrRenderAttrs(_cssVars)}>你好</span><span${_ssrRenderAttrs(_cssVars)}>${_ssrInterpolate(_ctx.msg)}</span><!--]-->`)
}

动态节点还是需要动态渲染

tree-shaking

编译时,根据不同的情况,引入不同的 API

<span>你好</span>

编译后

import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock("span", null, "你好"))
}

再增加一个动态节点

<span>你好</span>
<span>{{msg}}</span>

编译后

import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"export function render(_ctx, _cache, $props, $setup, $data, $options) {return (_openBlock(), _createElementBlock(_Fragment, null, [_createElementVNode("span", null, "你好"),_createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */)], 64 /* STABLE_FRAGMENT */))
}

可见因增加了动态节点,增加了 import 的 API,如 createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, Fragment as _Fragment


http://www.ppmy.cn/ops/3925.html

相关文章

PTA L2-047 锦标赛

题目 解析 把每一场比赛看作满二叉树的一个节点&#xff0c;父节点递归遍历子节点的结果&#xff0c;进行试填。 代码 #include <bits/stdc.h>using i64 long long;struct Node {int win, lose; };void solve() {int k;std::cin >> k;int siz (1 << k);…

面试:lock 和 synchronized

一、语法层面 synchronized 是关键字&#xff0c;源码在jvm中&#xff0c;用c语言实现Lock 是接口&#xff0c;源码由jdk提供&#xff0c;用java语言实现使用synchronized时&#xff0c;退出同步代码块锁会自动释放&#xff0c;而使用Lock时&#xff0c;需要手动调用unlock方法…

BOOT和UBOOT区别与联系

一、定义 1.1 Boot&#xff08;启动&#xff09; 在计算机和嵌入式系统的基本概念中&#xff0c;“boot”是指启动过程&#xff0c;这是一个系统从加电开始直至进入操作系统运行状态的过程。在嵌入式系统中&#xff0c;这个过程通常包括初始化硬件、加载并执行引导加载…

虚拟机下如何使用Docker(完整版)

Docker详细介绍&#xff1a; Docker 是一款开源的应用容器引擎&#xff0c;由Docker公司最初开发并在2013年发布。Docker的核心理念源自于操作系统级别的虚拟化技术&#xff0c;尤其是Linux上的容器技术&#xff08;如LXC&#xff09;&#xff0c;它为开发人员和系统管理员提供…

docker部署SpringCloud微服务项目

我们写好的项目&#xff0c;都需要部署上线&#xff0c;今天就给大家介绍一下&#xff0c;如何将微服务项目部署上线&#xff0c;一般我们部署项目都是先在本地docker部署一遍&#xff0c;如果没有问题再部署到服务器&#xff0c;那么今天我就按照这个顺序来说 前置条件 微服…

【C++】List容器(1)-STL标准库-List举例说明-定义和初始化-成员函数的使用-运行效率对比-链接数据结构-和顺序表的对比

C学习&#xff1a;list容器详解&#xff08;一&#xff09; 1.STL标准库 C Standard Template Library&#xff08;STL&#xff09;是C编程语言的一个库&#xff0c;它提供了一系列模板化的数据结构&#xff08;比如向量、列表、队列等&#xff09;和算法&#xff08;比如排序…

超越GPT-4V,苹果多模态大模型上新,神经形态计算加速MLLM(一)

4月8日&#xff0c;苹果发布了其最新的多模态大语言模型&#xff08;MLLM &#xff09;——Ferret-UI&#xff0c;能够更有效地理解和与屏幕信息进行交互&#xff0c;在所有基本UI任务上都超过了GPT-4V&#xff01; 苹果开发的多模态模型Ferret-UI增强了对屏幕的理解和交互&am…

游戏前摇后摇Q闪E闪QE闪QA等操作

备注&#xff1a;未经博主允许禁止转载 个人笔记&#xff08;整理不易&#xff0c;有帮助&#xff0c;收藏点赞评论&#xff0c;爱你们&#xff01;&#xff01;&#xff01;你的支持是我写作的动力&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_w…