Vue3.0性能提升主要是通过哪几方面体现的?

更新日期: 2022-12-22阅读: 622标签: Vue3

一、编译阶段

回顾vue2,我们知道每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把用到的数据property记录为依赖,当依赖发生改变,触发setter,则会通知watcher,从而使关联的组件重新渲染


试想一下,一个组件结构如下图

<template>
    <div id="content">
        <p class="text">静态文本</p>
        <p class="text">静态文本</p>
        <p class="text">{{ message }}</p>
        <p class="text">静态文本</p>
        ...
        <p class="text">静态文本</p>
    </div>
</template>

可以看到,组件内部只有一个动态节点,剩余一堆都是静态节点,所以这里很多 diff 和遍历其实都是不需要的,造成性能浪费

因此,Vue3在编译阶段,做了进一步优化。主要有如下:

  • diff算法优化
  • 静态提升
  • 事件监听缓存
  • SSR优化

diff算法优化

vue3在diff算法中相比vue2增加了静态标记

关于这个静态标记,其作用是为了会发生变化的地方添加一个flag标记,下次发生变化的时候直接找该地方进行比较

下图这里,已经标记静态节点的p标签在diff过程中则不会比较,把性能进一步提高


关于静态类型枚举如下

export const enum PatchFlags {
  TEXT = 1,// 动态的文本节点
  CLASS = 1 << 1,  // 2 动态的 class
  STYLE = 1 << 2,  // 4 动态的 style
  PROPS = 1 << 3,  // 8 动态属性,不包括类名和样式
  FULL_PROPS = 1 << 4,  // 16 动态 key,当 key 变化时需要完整的 diff 算法做比较
  HYDRATE_EVENTS = 1 << 5,  // 32 表示带有事件监听器的节点
  STABLE_FRAGMENT = 1 << 6,   // 64 一个不会改变子节点顺序的 Fragment
  KEYED_FRAGMENT = 1 << 7, // 128 带有 key 属性的 Fragment
  UNKEYED_FRAGMENT = 1 << 8, // 256 子节点没有 key 的 Fragment
  NEED_PATCH = 1 << 9,   // 512
  DYNAMIC_SLOTS = 1 << 10,  // 动态 solt
  HOISTED = -1,  // 特殊标志是负整数表示永远不会用作 diff
  BAIL = -2 // 一个特殊的标志,指代差异算法
}

静态提升

Vue3中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用

这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用

<span>你好</span>

<div>{{ message }}</div>

没有做静态提升之前

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock(_Fragment, null, [
    _createVNode("span", null, "你好"),
    _createVNode("div", null, _toDisplayString(_ctx.message), 1 /* TEXT */)
  ], 64 /* STABLE_FRAGMENT */))
}

做了静态提升之后

const _hoisted_1 = /*__PURE__*/_createVNode("span", null, "你好", -1 /* HOISTED */)

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock(_Fragment, null, [
    _hoisted_1,
    _createVNode("div", null, _toDisplayString(_ctx.message), 1 /* TEXT */)
  ], 64 /* STABLE_FRAGMENT */))
}

// Check the console for the AST

静态内容_hoisted_1被放置在render 函数外,每次渲染的时候只要取 _hoisted_1 即可

同时 _hoisted_1 被打上了 PatchFlag ,静态标记值为 -1 ,特殊标志是负整数表示永远不会用于 Diff

事件监听缓存

默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化

<div>
  <button @click = 'onClick'>点我</button>
</div>

没开启事件监听器缓存

export const render = /*__PURE__*/_withId(function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("button", { onClick: _ctx.onClick }, "点我", 8 /* PROPS */, ["onClick"])
                                             // PROPS=1<<3,// 8 //动态属性,但不包含类名和样式
  ]))
})

开启事件侦听器缓存后

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createBlock("div", null, [
    _createVNode("button", {
      onClick: _cache[1] || (_cache[1] = (...args) => (_ctx.onClick(...args)))
    }, "点我")
  ]))
}

上述发现开启了缓存后,没有了静态标记。也就是说下次diff算法的时候直接使用

SSR优化

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

div>
	<div>
		<span>你好</span>
	</div>
	...  // 很多个静态属性
	<div>
		<span>{{ message }}</span>
	</div>
</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(_mergeProps(_attrs, _cssVars))
  }><div><span>你好</span>...<div><span>你好</span><div><span>${
    _ssrInterpolate(_ctx.message)
  }</span></div></div>`)
}

二、源码体积

相比Vue2,Vue3整体体积变小了,除了移出一些不常用的api,再重要的是Tree shanking

任何一个函数,如ref、reavtived、computed等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小

import { computed, defineComponent, ref } from 'vue';
export default defineComponent({
    setup(props, context) {
        const age = ref(18)

        let state = reactive({
            name: 'test'
        })

        const readOnlyAge = computed(() => age.value++) // 19

        return {
            age,
            state,
            readOnlyAge
        }
    }
});

三、响应式系统

vue2中采用 defineProperty来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加getter和setter,实现响应式

vue3采用proxy重写了响应式系统,因为proxy可以对整个对象进行监听,所以不需要深度遍历

  • 可以监听动态属性的添加
  • 可以监听到数组的索引和数组length属性
  • 可以监听删除属性
来源:https://vue3js.cn/interview/vue3/performance.html

链接: https://www.fly63.com/article/detial/12277

vue3.x 新特性 - CompositionAPI

安装 vue-cli3,在使用任何 @vue/composition-api 提供的能力前,必须先通过 Vue.use() 进行安装,安装插件后,您就可以使用新的 Composition API 来开发组件了。

Vue3数据响应系统

Vue3 就是基于 Proxy 对其数据响应系统进行了重写,现在这部分可以作为独立的模块配合其他框架使用。数据响应可分为三个阶段: 初始化阶段 --> 依赖收集阶段 --> 数据响应阶段

快速进阶Vue3.0

在2019.10.5日发布了Vue3.0预览版源码,但是预计最早需要等到 2020 年第一季度才有可能发布 3.0 正式版。新版Vue 3.0计划并已实现的主要架构改进和新功能:

Vue 3 对 Web 应用性能的改进

有关即将发布的 Vue.js 的第 3 个主要版本的信息越来越多。通过下面的讨论,虽然还不能完全确定其所有内容,但是我们可以放心地认为,它将是对当前版本(已经非常出色)的巨大改进。 Vue 团队在改进框架 API 方面做得非常出色

Vue3 中令人兴奋的新功能

用新的 Vue 3 编写的程序效果会很好,但性能并不是最重要的部分。对开发人员而言,最重要的是新版本将会怎样影响我们编写代码的方式。如你所料,Vue 3 带来了许多令人兴奋的新功能。值得庆幸的是

200 行从零实现 vue3

emmm 用半天时间捋顺了 vue3 的源码,再用半天时间写了个 mini 版……我觉得我也是没谁了,vue3 的源码未来一定会烂大街的,我们越早的去复现它,就……emm可以越早的装逼hhh

从 Proxy 到 Vue 源码,深入理解 Vue 3.0 响应系统

10 月 5 日,尤雨溪在 GitHub 开放了 Vue 3.0 处于 pre-alpha 状态的源码,这次 Vue 3.0 Updates 版本的更新,将带来五项重大改进:速度体积、可维护性、面向原生、易用性

Vue 的数据响应式(Vue2 及 Vue3)

从一开始使用 Vue 时,对于之前的 jq 开发而言,一个很大的区别就是基本不用手动操作 dom,data 中声明的数据状态改变后会自动重新渲染相关的 dom。换句话说就是 Vue 自己知道哪个数据状态发生了变化及哪里有用到这个数据需要随之修改。

在Vue2与Vue3中构建相同的组件

Vue 开发团队终于在今天发布了 3.0-beta.1 版本,也就是测试版。通常来说,从测试版到正式版,只会修复 bug,不会引入新功能,或者删改老功能。所以,如果你对新版本非常感兴趣,或者有新项目即将上马,不妨尝试一下新版本

Vue3中的Vue Router初探

对于大多数单页应用程序而言,管理路由是一项必不可少的功能。随着新版本的Vue Router处于Alpha阶段,我们已经可以开始查看下一个版本的Vue中它是如何工作的。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!