计算机系统应用教程网站

网站首页 > 技术文章 正文

Vue3.0 做了哪些优化,VUE3有哪些功能 proxy代替defineProperty

btikc 2024-09-06 18:12:56 技术文章 19 ℃ 0 评论

一、设计目标

不以解决实际业务痛点的更新都是耍流氓,下面我们来列举一下Vue3之前我们或许会面临的问题

  • 随着功能的增长,复杂组件的代码变得越来越难以维护
  • 缺少一种比较「干净」的在多个组件之间提取和复用逻辑的机制
  • 类型推断不够友好
  • bundle的时间太久了

Vue3 经过长达两三年时间的筹备,做了哪些事情?

我们从结果反推

  • 更小
  • 更快
  • TypeScript支持
  • API设计一致性
  • 提高自身可维护性
  • 开放更多底层功能

一句话概述,就是更小更快更友好了

更小

Vue3移除一些不常用的 API

引入tree-shaking,可以将无用模块“剪辑”,仅打包需要的,使打包的整体体积变小了

更快

主要体现在编译方面:

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

下篇文章我们会进一步介绍

更友好

vue3在兼顾vue2options API的同时还推出了composition API,大大增加了代码的逻辑组织和代码复用能力

这里代码简单演示下:

存在一个获取鼠标位置的函数

import { toRefs, reactive } from 'vue';
function useMouse(){
    const state = reactive({x:0,y:0});
    const update = e=>{
        state.x = e.pageX;
        state.y = e.pageY;
    }
    onMounted(()=>{
        window.addEventListener('mousemove',update);
    })
    onUnmounted(()=>{
        window.removeEventListener('mousemove',update);
    })

    return toRefs(state);
}


我们只需要调用这个函数,即可获取xy的坐标,完全不用关注实现过程

试想一下,如果很多类似的第三方库,我们只需要调用即可,不必关注实现过程,开发效率大大提高

同时,VUE3是基于typescipt编写的,可以享受到自动的类型定义提示

三、优化方案

vue3从很多层面都做了优化,可以分成三个方面:

  • 源码
  • 性能
  • 语法 API

源码

源码可以从两个层面展开:

  • 源码管理
  • TypeScript

源码管理

vue3整个源码是通过 monorepo的方式维护的,根据功能将不同的模块拆分到packages目录下面不同的子目录中

这样使得模块拆分更细化,职责划分更明确,模块之间的依赖关系也更加明确,开发人员也更容易阅读、理解和更改所有模块源码,提高代码的可维护性

另外一些 package(比如 reactivity 响应式库)是可以独立于 Vue 使用的,这样用户如果只想使用 Vue3的响应式能力,可以单独依赖这个响应式库而不用去依赖整个 Vue

TypeScript

Vue3是基于typeScript编写的,提供了更好的类型检查,能支持复杂的类型推导

性能

首先是相对Vue2的一些性能改进:

  • 通过摇树(减轻了多达41%的资源大小)
  • 初始渲染(加快了多达55%的速度)
  • 更新速度:(加快了133%的速度)
  • 内存占用:(最多减少54%)

其次还带来一些新的的优化,简单总结下

  • 路由懒加载
  • keep-alive缓存页面
  • 使用v-show复用DOM
  • v-for 遍历避免同时使用 v-if
  • 长列表性能优化
  • 事件的销毁
  • 图片懒加载
  • 第三方插件按需引入
  • 无状态的组件标记为函数式组件
  • 子组件分割
  • 变量本地化
  • SSR

vue3是从什么哪些方面对性能进行进一步优化呢?

  • 体积优化
  • 编译优化
  • 数据劫持优化

这里讲述数据劫持:

vue2中,数据劫持是通过Object.defineProperty,这个 API 有一些缺陷,并不能检测对象属性的添加和删除

Object.defineProperty(data, 'a',{
  get(){
    // track
  },
  set(){
    // trigger
  }
})


尽管Vue为了解决这个问题提供了 setdelete实例方法,但是对于用户来说,还是增加了一定的心智负担

同时在面对嵌套层级比较深的情况下,就存在性能问题

default {
  data: {
    a: {
      b: {
          c: {
          d: 1
        }
      }
    }
  }
}


相比之下,vue3是通过proxy监听整个对象,那么对于删除还是监听当然也能监听到

同时Proxy 并不能监听到内部深层次的对象变化,而 Vue3 的处理方式是在getter 中去递归响应式,这样的好处是真正访问到的内部对象才会变成响应式,而不是无脑递归

更好的TypeScript集成

  • 改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告
  • 更好地调试支持

语法 API

这里当然说的就是composition API,其两大显著的优化:

  • 优化逻辑组织
  • 优化逻辑复用
  • reactive
  • ref
  • computed
  • readonly
  • watchEffect
  • watch
  • unref
  • toRef
  • toRefs
  • isRef
  • isProxy
  • isReactive
  • isReadonly
  • customRef
  • markRaw
  • shallowReactive
  • shallowReadonly
  • shallowRef
  • toRaw

逻辑组织

一张图,我们可以很直观地感受到 Composition API在逻辑组织方面的优势

相同功能的代码编写在一块,而不像options API那样,各个功能的代码混成一块

composition-api,旨在解决大型应用程序中Vue使用的难点。是Vue3.0最重要的RFC(官方文档)原来叫vue-function-api。

Composition API建立在反应性API之上,与2.x基于对象的API相比,可实现类似于React挂钩的逻辑组成和重用,更灵活的代码组织模式以及更可靠的类型推断。

下面是一个官网的例子:

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  </button>
</template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
</script>

逻辑复用

vue2中,我们是通过mixin实现功能混合,如果多个mixin混合,会存在两个非常明显的问题:命名冲突和数据来源不清晰

而通过composition这种形式,可以将一些复用的代码抽离出来作为一个函数,只要的使用的地方直接进行调用即可

同样是上文的获取鼠标位置的例子

import { toRefs, reactive, onUnmounted, onMounted } from 'vue';
function useMouse(){
    const state = reactive({x:0,y:0});
    const update = e=>{
        state.x = e.pageX;
        state.y = e.pageY;
    }
    onMounted(()=>{
        window.addEventListener('mousemove',update);
    })
    onUnmounted(()=>{
        window.removeEventListener('mousemove',update);
    })

    return toRefs(state);
}

组件使用

import useMousePosition from './mouse'
export default {
    setup() {
        const { x, y } = useMousePosition()
        return { x, y }
    }
}

可以看到,整个数据来源清晰了,即使去编写更多的hook函数,也不会出现命名冲突的问题

分层内部模块

Vue 3.0内核仍然可以通过一个简单的<script>标签使用,但其内部结构已被彻底重写为一组解耦的模块。新的体系结构提供了更好的可维护性,并允许最终用户通过摇树来减少运行时大小的一半。

模块提供的功能点:

  1. 编译器支持用于构建时自定义的自定义AST转换(例如,构建时i18n)
  2. 核心运行时提供API用于创建针对不同渲染目标(例如本机移动设备,WebGL或终端)的自定义渲染器。默认DOM渲染器使用相同的API构建。
  3. 该@vue/reactivity模块导出的功能可以直接访问Vue的反应系统,并且可以用作独立程序包。它可以与其他模板解决方案(例如lit-html)配对,甚至可以用于非UI方案。

Vue3六大亮点

1.性能比Vue2快1.2~2倍;

2.Vue3 按需编译,体积比Vue2更小

3.支持组合API,类似React Hooks

4.更好的支持TS

5.暴露了自定义渲染的API

6.提供了更先进的组件

如何提速

1.Vue3对diff算法进行了优化:

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

2.静态提升:

Vue2中,无论元素是否参与更新,每次都会重新创建,Vue3中对于不参与更新的元素,会做静态提升,只创建一次,之后会在每次被渲染时不停复用,创建次数少了,性能就提升了。

3.事件侦听器缓存

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

4.ssr渲染

当有大量静态内容时,这些内容会被当成纯字符串推进一个buffer里面,即使存在动态的绑定,会通过插值嵌入进去。这样会比通过虚拟dom来渲染快很多。当静态内容大到一定量级的时候,会用_createStaticVNode方法在在客户端去生成一个static node,这些静态node会被直接innerHTML,就不需要创建对象,然后直接根据对象渲染。

vue3快速上手

创建方式有三种:Vue-CLI、Webpack、Webpack、Vite。前三种不做说明。

Vite介绍:Vite是Vue作者为vue3定制开发的工具,由意图取代Webpack。其实现原理是利用ES6的import会发送请求,去加载文件的特性,拦截这些请求,做一些预编译,省去了webpack冗长的打包时间。

1.安装Vite:

npm install -g create-vite-app

2.创建vue3项目:

create-Vite-app projectName

3.安装依赖运行项目

cd projectName

npm install

proxy代替defineProperty

Vue2.0双向绑定

  • observer遍历对象,在getter/setter方法中拦截对对象属性的读写操作
  • 对象拦截:可拦截对象属性更改,不能拦截对象属性增删
  • 数组拦截:通过重写prototype,可拦截7种数组方法,不能拦截数组直接赋值、长度变更

Vue3.0双向绑定

  • proxy支持劫持对象的属性增删和数组的索引操作
  • 对比Vue2.0对data递归劫持数据,Vue3提供reactive等方法自定义响应式数据,节省内存开销
  • IE11兼容性问题,vue会提供兼容版本

速度提升一倍:

给大家分享我收集整理的各种学习资料,前端小白交流、学习交流,也可以直接问我,我会组织大家一起做项目练习,帮助大家匹配一位学习伙伴互相监督学习-下面是学习资料参考。

前端学习交流、自学、学习资料等推荐 - 知乎

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表