为何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

相关推荐

  1. Vue3 Vue2 有什么优势?

    2024-07-23 04:56:06       24 阅读
  2. vue2vue3

    2024-07-23 04:56:06       32 阅读
  3. vue2-vue3面试

    2024-07-23 04:56:06       27 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-23 04:56:06       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-23 04:56:06       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-23 04:56:06       45 阅读
  4. Python语言-面向对象

    2024-07-23 04:56:06       55 阅读

热门阅读

  1. 数学建模(5)——逻辑回归

    2024-07-23 04:56:06       14 阅读
  2. SpringMVC中的注解驱动

    2024-07-23 04:56:06       14 阅读
  3. C 语言基础概念总结

    2024-07-23 04:56:06       17 阅读
  4. word转pdf图变得模糊(解决)

    2024-07-23 04:56:06       14 阅读
  5. Nginx 中如何实现请求的排队机制?

    2024-07-23 04:56:06       16 阅读
  6. 2024.07.14校招 实习 内推 面经

    2024-07-23 04:56:06       18 阅读
  7. 【开源库学习】libodb库学习(十)

    2024-07-23 04:56:06       13 阅读
  8. 【Python】探索 Python 中的 divmod 方法

    2024-07-23 04:56:06       13 阅读