vue 3.0学习1

本文深入探讨Vue3.0的性能提升,重点讲解了Diff算法的优化,如静态标记(PatchFlags)的使用,提高了对比效率;介绍了静态提升(hoistStatic)技术,减少重复创建;详细阐述了事件侦听器缓存(cacheHandlers)机制,避免不必要的追踪;并讨论了SSR渲染的改进,提升大规模静态内容的处理速度。通过这些优化,Vue3.0实现了比Vue2.x更快的运行速度和更小的体积。
摘要由CSDN通过智能技术生成

一、vue 3.0 diff算法优化

1.vue 3.0六大亮点

  • Performance:性能比Vue 2. x快1.2 ~2倍
  • Tree shaking support: 按需编译,体积比Vue2. x更小
  • Composition API: 组合API (类似React Hooks)
  • Better TypeScript support: 更好的Ts支持
  • Custom Renderer API: 暴露了自定义渲染API
  • Fragment, Teleport (Protal),Suspense: 更先进的组件

2.vue 3.0 如何变快的?

1. diff方法优化 https://vue-next-template-explorer.netlify.app

Vue2中的虚拟dom是进行全量的对比
Vue3新增了静态标记(PatchFlag),
在与上次虚拟节点进行对比时候,只对比带有patch flag的节点 并且可以通过flag的信息得知当前节点要对比的具体内容

在这里插入图片描述

代码示例 vue3.0 编译模板的优化

vue 3.0编译模板网址

<div>Hello World!</div>
<div>我和我的祖国</div>
<div>{{msg}}</div>
<div :id="uid">{{name}}</div>
export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock(_Fragment, null, [
    _createVNode("div", null, "Hello World!"),
    _createVNode("div", null, "我和我的祖国"),
    _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createVNode("div", { id: _ctx.uid }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
  ], 64 /* STABLE_FRAGMENT */))
}

注意看第三个_createVNode结尾的“1”: Vue 在运行时会生成number(大于 0)值的PatchFlag,用作标记。

仅带有PatchFlag标记的节点会被真正追踪,且无论层级嵌套多深,它的动态节点都直接与Block根节点绑定,无需再去遍历静态节点

第四个 PatchFlag 变成了9 / TEXT, PROPS /, [“id”]
它会告知我们不光有TEXT变化,还有PROPS变化(id) 这样既跳出了virtual
dom性能的瓶颈,又保留了可以手写render的灵活性。 等于是:既有react的灵活性,又有基于模板的性能保证。

附录: PatchFlags

export const enum PatchFlags{
TEXT = 1,//动态文本节点
CLASS=1<<1,//2//动态class
STYLE=1<<2,//4//动态style
PROPS=1<<3,//8//动态属性,但不包含类名和样式
FULLPROPS=1<<4,//16//具有动态key属性,当key改变时,需要进行完整的diff比较。
HYDRATE_EVENTS=1<<5,//32//带有监听事件的节点
STABLE FRAGMENT = 1 << 6, // 64 //一个不会改变子节点顺序的fragment
KEYED FRAGMENT = 1 << 7, // 128 //带有key 属性的fragment 或部分子字节有key
UNKEYED FRAGMENT = 1 << 8, // 256 //子节点没有key 的fragment
NEED PATCH = 1 << 9, // 512 //一个节点只会进行非props比较
DYNAMIC_ SLOTS = 1 << 10, // 1024 //动态slot
HOISTED = -1, //静态节点
//指示在diff过程应该要退出优化模式
BAIL= -2

2. hoistStatic静态提升

Vue2中无论元素是否参与更新,每次都会重新创建
Vue3中对于不参与更新的元素,只会被创建一次,之后会在每次渲染时候被不停的复用

<div>Hello World!</div>
<div>我和我的祖国</div>
<div>{{msg}}</div>
<div :id="uid">{{name}}</div>

静态提升之前:

	export function render(_ctx, _cache, $props, $setup, $data, $options) {
	  return (_openBlock(), _createBlock(_Fragment, null, [
	    _createVNode("div", null, "Hello World!"),
	    _createVNode("div", null, "我和我的祖国"),
	    _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
	    _createVNode("div", { id: _ctx.uid }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
	  ], 64 /* STABLE_FRAGMENT */))
	}

静态提升之后:

	const _hoisted_1 = /*#__PURE__*/_createVNode("div", null, "Hello World!", -1 /* HOISTED */)
	const _hoisted_2 = /*#__PURE__*/_createVNode("div", null, "我和我的祖国", -1 /* HOISTED */)
	
	export function render(_ctx, _cache, $props, $setup, $data, $options) {
	  return (_openBlock(), _createBlock(_Fragment, null, [
	    _hoisted_1, //直接复用
	    _hoisted_2, //直接复用
	    _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
	    _createVNode("div", { id: _ctx.uid }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
	  ], 64 /* STABLE_FRAGMENT */))
	}

3. cacheHandlers事件侦听器缓存

默认情况下onClick会被视为动态绑定,所以每次都会去追踪它的变化
但是因为是同一个函数,所以没有追踪变化,直接缓存起来复用即可

事件监听缓存
<button @click="inc">按钮</button>

开启事件监听缓存之前:

	export function render(_ctx, _cache, $props, $setup, $data, $options) {
	  return (_openBlock(), _createBlock("button", { onClick: _ctx.inc }, "按钮", 8 /* PROPS */, ["onClick"]))
	}

开启事件监听缓存之后:

	export function render(_ctx, _cache, $props, $setup, $data, $options) {
	  return (_openBlock(), _createBlock("button", {
	    onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.inc(...args)))
	  }, "按钮"))
	}

注意点:转换之后的代码,可能还看不懂,但是不要紧
我们只需要观察有没有静态标记即可
因为我们知道在Vue3的diff算法中,只有有静态标记的才会进行比较,才会进行追踪

4. ssr渲染

当有大量静态的内容时候,这些内容会被当做纯字符串推进一个buffer里面,
即使存在动态的绑定,会通过模板插值嵌入进去。这样会比通过虚拟dmo来渲染的快上很多很多。

当静态内容大到一定量级时候, 会用_createStaticVNode方法在 客户端去生成个static node.
这些静态node,会被直接innerHtml,就不需要创建对象,然后根据对象渲染。

代码示例
	<div>Hello World!</div>
	<div>我和我的祖国</div>
	<div>{{msg}}</div>
	<div :id="uid">{{name}}</div>

开启ssr渲染之前:

	export function render(_ctx, _cache, $props, $setup, $data, $options) {
	  return (_openBlock(), _createBlock(_Fragment, null, [
	    _createVNode("div", null, "Hello World!"),
	    _createVNode("div", null, "我和我的祖国"),
	    _createVNode("div", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
	    _createVNode("div", { id: _ctx.uid }, _toDisplayString(_ctx.name), 9 /* TEXT, PROPS */, ["id"])
	  ], 64 /* STABLE_FRAGMENT */))
	}

开启ssr渲染之后:

	export function ssrRender(_ctx, _push, _parent, _attrs, $props, $setup, $data, $options) {
	  const _cssVars = _ssrResolveCssVars({ color: _ctx.color })
	  _push(`<!--[--><div${
	    _ssrRenderAttrs(_cssVars)
	  }>Hello World!</div><div${
	    _ssrRenderAttrs(_cssVars)
	  }>我和我的祖国</div><div${
	    _ssrRenderAttrs(_cssVars)
	  }>${
	    _ssrInterpolate(_ctx.msg)
	  }</div><div${
	    _ssrRenderAttrs(_mergeProps({ id: _ctx.uid }, _cssVars))
	  }>${
	    _ssrInterpolate(_ctx.name)
	  }</div><!--]-->`)
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值