为何Vue3比Vue2快

Proxy响应式

PatchFlag

  • 编译模板时,动态节点做标记
  • 标记,分为不同的类型,如TEXT PROPS
  • diff算法时,可以区分静态节点,以及不同类型的动态节点
<div>Hello World</div>
<span>{{ msg }}</span>
<span class="msg">闻人放歌</span>
<span id="name">{{ msg }}</span>
<span class="msg-class" :msg="message">{{ 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("div", null, "Hello World"),
    _createElementVNode("span", null, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createElementVNode("span", { class: "msg" }, "闻人放歌"),
    _createElementVNode("span", { id: "name" }, _toDisplayString(_ctx.msg), 1 /* TEXT */),
    _createElementVNode("span", {
      class: "msg-class",
      msg: _ctx.message
    }, _toDisplayString(_ctx.msg), 9 /* TEXT, PROPS */, ["msg"])
  ], 64 /* STABLE_FRAGMENT */))
}

// Check the console for the AST

在这里插入图片描述
静态字段将不再比较,这样diff算法将少比较很多节点。

hoistStatic

  • 将静态节点的定义,提升到父作用域,缓存起来
  • 多个相邻的静态节点,会被合并起来
  • 典型的拿空间换时间的优化策略
//  模板
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>

编译结果:

import { createElementVNode as _createElementVNode, createCommentVNode as _createCommentVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createElementVNode("div", null, "Hello World", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createElementVNode("div", null, "Hello World", -1 /* HOISTED */)
const _hoisted_3 = /*#__PURE__*/_createElementVNode("div", null, "Hello World", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(_Fragment, null, [
    _hoisted_1,
    _hoisted_2,
    _hoisted_3,
    _createCommentVNode(" <span>{{ msg }}</span>\n<span class=\"msg\">闻人放歌</span>\n<span id=\"name\">{{ msg }}</span>\n<span class=\"msg-class\" :msg=\"message\">{{ msg }}</span> ")
  ], 64 /* STABLE_FRAGMENT */))
}

// Check the console for the AST

还有一个点,如果静态节点数量多,编译会自动合并,如:

<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
import { createElementVNode as _createElementVNode, createCommentVNode as _createCommentVNode, createStaticVNode as _createStaticVNode, Fragment as _Fragment, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

const _hoisted_1 = /*#__PURE__*/_createStaticVNode("<div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div><div>Hello World</div>", 10)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(_Fragment, null, [
    _hoisted_1,
    _createCommentVNode(" <span>{{ msg }}</span>\n<span class=\"msg\">闻人放歌</span>\n<span id=\"name\">{{ msg }}</span>\n<span class=\"msg-class\" :msg=\"message\">{{ msg }}</span> ")
  ], 2112 /* STABLE_FRAGMENT, DEV_ROOT_FRAGMENT */))
}

// Check the console for the AST

cacheHandler

上代码:

<div @click="clickHandler">Hello World</div>

编译结果:

import { openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("div", {
    onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.clickHandler && _ctx.clickHandler(...args)))
  }, "Hello World"))
}

// Check the console for the AST

从编译结果代码可以看出,如果该事件方法已被定义则直接去缓存中的方法,没有则定义。其意义就是缓存事件

SSR优化

编译前:

<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>Hello World</div>
<div>{{ msg }}</div>
<div @click="clickHandler">Hello World</div>
<div class="msg-class">{{ msg }}</div>
<div class="msg-class" :msg="msg">闻人放歌</div>

编译结果:

import { mergeProps as _mergeProps } from "vue"
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(`<!--[--><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_cssVars)
  }>${
    _ssrInterpolate(_ctx.msg)
  }</div><div${
    _ssrRenderAttrs(_cssVars)
  }>Hello World</div><div${
    _ssrRenderAttrs(_mergeProps({ class: "msg-class" }, _cssVars))
  }>${
    _ssrInterpolate(_ctx.msg)
  }</div><div${
    _ssrRenderAttrs(_mergeProps({
      class: "msg-class",
      msg: _ctx.msg
    }, _cssVars))
  }>闻人放歌</div><!--]-->`)
}

// Check the console for the AST
  • 静态节点直接输出,绕过了vdom
  • 动态节点,还是需要动态渲染

tree-shaking

观察两者编译结果区别:

<div v-if="msg">Hello World</div>
<input v-model="msg">
// 编译结果
import { openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode, vModelText as _vModelText, createElementVNode as _createElementVNode, withDirectives as _withDirectives, Fragment as _Fragment } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock(_Fragment, null, [
    (_ctx.msg)
      ? (_openBlock(), _createElementBlock("div", { key: 0 }, "Hello World"))
      : _createCommentVNode("v-if", true),
    _withDirectives(_createElementVNode("input", {
      "onUpdate:modelValue": $event => ((_ctx.msg) = $event)
    }, null, 8 /* PROPS */, ["onUpdate:modelValue"]), [
      [_vModelText, _ctx.msg]
    ])
  ], 64 /* STABLE_FRAGMENT */))
}

// Check the console for the AST

<div v-if="msg">Hello World</div>

// 编译结果
import { openBlock as _openBlock, createElementBlock as _createElementBlock, createCommentVNode as _createCommentVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_ctx.msg)
    ? (_openBlock(), _createElementBlock("div", { key: 0 }, "Hello World"))
    : _createCommentVNode("v-if", true)
}

// Check the console for the AST

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

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值