Vue 3 新特性

更快、更小、更易于维护

1. 更快

更快主要体现在 Vue 3 在性能方面的提升,以及在源码层面的改动,主要包括以下方面:

  • 重构虚拟 DOM。
  • 事件缓存。
  • 基于Proxy 的响应式对象

(1) 重构虚拟 DOM
        Vue 3 重写了虚拟 DOM的实现方法,使得初始染/更新可以提速达 100%,对于 Vue 2.x版本的虚拟 DOM 来说,Vue 会遍历<template>模板中的所有内容,并根据这些标签生成对应的虚拟DOM(虚拟 DOM 一般指采用 kev/value 对象来保存标签元素的属性和内容),当有内容改变时遍历虚拟 DOM 来找到变化前后不同的内容,我们称这个过程叫作 diff (different),并找到针对这些变化的内容所对应的 DOM 节点,并改变其内部属性。例如下面这段代码:

<template>
    <div class="content">
        <p>number1</p>
        <p>number2</p>
        <p>number3</p>
        <p>{{count}}</p>
    </div>
</template>

        当触发响应式时,遍历所有的<div>标签和<p>标签,找到{{count}变量对应的<p>标签的 DON节点,并改变其内容。对于那些纯静态<p>标签的节点进行 diff 其实比较浪费资源的,当节点的数量很少时,表现并不明显,但是一旦节点的数量过大,在性能上就会慢很多。对此,Vue 3 在此基础上进行了优化,主要有:

  • 标记静态内容,并区分动态内容 (静态提升)
  • 更新时只 diff 动态部分。

        针对上面的代码,Vue3 中首先会区分出{{count}}这部分动态的节点,在进行 diff 时,只针对这些节点进行,从而减少资源浪费,提升性能。 

(2)事件缓存
        我们知道在 Vue 2.x 中,在绑定 DOM 事件时,例如@click,这些事件被认为是动态变量,所以每次更新视图的时候都会追踪它的变化,然后每次触发都要重新生成全新的函数。在 Vue 3中提供了事件缓存对象 cacheHandlers,当 cacheHandlers 开启的时候,@click 绑定的事件会被标记成静态节点,被放入 cacheHandlers 中,这样在视图更新时也不会追踪,当事件再次触发时,就无须重新生成函数,直接调用缓存的事件回调方法即可,在事件处理方面提升了 Vue 的性能。

        未开启 cacheHandlers 编译后的代码如下:

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

//编译后
export function render(_ctx, _cache, $props,$setup, sdata, soptions) {
    return (_openBlock(),_createElementBlock("div",{
        onClick:_ctx, _cache.hi}, "Hello World1",
8 /* PROPS */,["onClick"]))
}

        开启 cacheHandlers 编译后的代码如下:

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

// 编译后
export function render(_ctx, _cache, $props, $setup, $data, Soptions) {
    return (_openBlock(), _createElementBlock("div", {
        onClick: _cache[0] || (_cache[0] = (...args) => (_ctx.hi && _ctx.hi(...args)))
    },"Hello worldl"))
}

        可以看到主要区别在于 onClick 那一行,直接从缓存中读取了回调函数

 (3)基于 Proxy的响应式对象
        在 Vue 2.x 中,使用 Object.defineProperty0来实现响应式对象,对于一些复杂的对象,需要循环递归地给每个属性增加 getter/setter 监听器,这使得组件的初始化非常耗时,而 Vue 3 中,引入了一种新的创建响应式对象的方法 reactive,其内部就是利用 ES6的 Proxy API来实现的,这样就可以不用针对每个属性来一一进行添加,以减少开销,提升性能。

 2.更小
        更小主要体现在包所占容量的大小,我们知道,前端资源一般都属于静态资源,例如 JavaSript文件、HTML 文件等,这些资源都托管在服务器上,用户在使用浏览器访问时,会将这些资源下载下来,所以精简文件包大小是提升页面性能的重要因素。Vue 3 在这方面可以让开发者打包构建出来的资源更小,从而提升性能。
        Tree Shaking 是一个术语,通常用于描述移除JavaScript 上下文中的未引用代码(dead-code),就像一棵大树,将那些无用的叶子都剪掉。它依赖于 ES 6模块语法的静态结构特性,例如import和export,这个术语和概念在打包工具 Rollup和 Webpack中普及开来。例如下面这段ES6代码:

import { get } from./api.js'

let doSome = () => {
    get()
}

doSome()

// api.js
export let post = () => {
    console.log('post')
}

export let get = () => {
    console.log('get')
}

        上面的代码中,api.is代码中的 post 方法相关内容是没有被引入和使用的,有了Tree Shaking之后,这部分内容是不会被打包的,这就在一定程度上减少了资源的大小。使用 Tree Shaking 的原理是引入了 ES6的模块静态分析,这就可以在编译时正确判断到底加载了什么代码,但是要注意import 和 export 是ES6 原生的,而不是通过 Babel或者 Webpack 转化的。

        在 Vue 3 中,对代码结构进行了优化,让其更加符合 Tree Shaking 的结构,这样使用相关的API时,就不会把所有的都打包进来,只会打包用户用到的 API,例如:

<!-- vue 2.x -->
import Vue fromivuer
new Vue()
Vue.nextTick(() => {})
const obj= Vue.observable({})

<!-- vue 3.x -->
import { nextTick, observable,createApp } from ivue!
nextTick(() => {})
const obj = observable({})
createApp({})

        同理,例如<keep-alive>、<transition>和<teleport>等内置组件,如果没有使用,也不会被打包到资源中。

3. 更易于维护

(1)从Flow 迁移到TypeScript
        TypeScript是微软开发的一个开源的编程语言,通过在JavaScript 的基础上添加静态类型定义构建而成,其通过 TypeScript 编译器或 Babel 转译为 JavaScript代码,可运行在任何浏览器和操作系统上。TypeScript引入了很多新的特性,例如类型监测、接口等,这些特性在框架源码的维护上有很大的提升。
在Vue 3的源码结构层面,从Flow 改成了TypeScript 来编写,Fow是一个静态类型检测器有了它就可以在 JavaScript 运行前找出常见的变量类型的 bug,类似于 Java 语言中给变量强制指定类型,它的功能主要包括:

  • 自动类型转换。
  • null 引用。
  • 处理 undefined is not a function。

例如:

// @flow

function foo(x: number): number {
    return x + 10
}

foo('hi') // 参数x须为 number 类型,否则会报错
错误信息:'[flow] string (This type is incompatible with number See also: function call)'

上面这段代码采用了 Flow 后,如果类型不对就会报错。一般来说,对于 JavaScript 源码框架,引入类型检测是非常重要的,不仅可以减少 bug 的产生,还可以规范一些接口的定义,这些特性和TypeScript 非常吻合,所以在 Vue 3 中直接采用了 TypeScript 来进行重写,从源码层面来提升项目的可维护性。

(2)源代码目录结构遵循 Monorepo
        Monorepo 是一种管理代码的方式,它的核心观点是所有的项目在一个代码仓库中,但是代码分割到一个个小的模块中,而不是都放在 src 这个目录下。这样的分割,使得每个开发者大部分时间只是工作在少数的几个文件夹内,并且也只会编译自己负责的模块,不会导致一个 IDE 打不开太大的项目之类的事情,这样很多事情就简单了很多。Monorepo 的结构如图所示。

        目前很多大型的框架(例如 Babel、React、Angular、Ember、Meteor、Jest 等)都采用了 Monorepo这种方式来进行源码的管理,当然在自己的业务项目中,也可以使用 Monorepo 来管理代码。我们可以看一下 Vue.is 在采用Monorepo 前后的源码结构对比,如图所示。

 Vue2.x 源码目录结构 (左)和Vue3x 源码目录结构(右)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值