[vue3] vue3对比vue2优化项简要概述

不足与展望

Vue2的不足

  1. 源码自身的可维护性较差;
  2. 数据量大后带来渲染和更新的性能问题;
  3. 存在一些为了兼容但是和鸡肋的API。

对Vue3的期望

  1. 更好的编程体验;
  2. 更好的TypeScript支持;
  3. 更好的逻辑复用实践。

源码性能语法API三大方面优化框架。

Vue3的优化

源码优化

源码优化的目的是让代码更易于开发和维护。

主要体现在使用monorepo管理源码仓库,以及使用TypeScript进行开发。

monorepo

monorepo将模块拆分到不同的package中,每个package拥有各自的API、类型定义和测试。

这样使得模块拆分更细化,职责划分更明确,模块之间的依赖关系也更加明确。

开发人员也更容易阅读、理解和更改所有模块源码,提高了代码的可维护性

image-20240803183604328

使用mororepo还有一个好处是:package可以独立于Vue.js使用,例如reactivity响应式库。

如果用户仅需要使用Vue.js 3.0的响应式功能,可以单独依赖这个package而不需要依赖整个Vue.js减小了引用包的体积大小

TypeScript

使用TypeScript的好处是:

  • 可以在编码阶段做类型检查;
  • 定义接口类型,有利于IDE对变量类型的推导,开发更轻松。

Vue曾经用过flow作为类型工具,但后来转TypeScript了,原因在于:

  • TypeScript的社区更活跃;
  • TypeScriptIDE中的支持更好;
  • TypeScript有明确的版本发布策略,使得维护和升级更加可控,Flow的团队后期烂尾。

一篇相关的文章:Flow vs Typescript: From Flow to Typescript. Why? - DEV Community

性能优化

减小包体积

  1. 移除一些冷门的feature,比如inline-template
  2. 引入tree-shaking技术。
tree-shaking

tree-shaking依赖ES2015的模块语法,通过编译阶段的静态分析,找到没有引入的模块并打上标记。

在项目中没有引入的模块或组件,它们对应的代码就不会被打包,也就间接减小了项目引入Vue.js包体积的目的。

数据劫持优化

Vue最独特的特性之一,是其非侵入性的响应式系统。

data

实现非侵入式的响应式系统的关键在于拦截对数据的读写操作

响应式数据需要配置gettersetter。当渲染函数执行时,读取了数据,触发getter,在getter中将object[key]到依赖的映射记录到Watcher中。

依赖是一个函数,对于在template中使用的响应式数据来说,它的依赖就是渲染函数。

当响应式数据被更新时,即被赋值,会触发setter,在setter中根据objectkeyWatcher中找到相对应的依赖函数,执行。即触发了视图更新。

总结

  • getter中使用track函数收集依赖;
  • setter中使用trigger函数触发更新。

Vue2的做法

Vue2中使用Object.defineProperty这个方法拦截对对象指定属性的读写操作。

Object.defineProperty为对象的指定属性设置gettersetter

对于一个嵌套层级较深的对象来说,为了遍历对象的每个属性,需要递归调用,为每个属性都设置getter&setter

缺点

  • 递归调用会导致性能较差;

  • 无法检测 property 的添加或移除,后来新增的属性无法实现响应式;

    需要使用全局的Vue.set方法或者组件内部局部的this.$set方法,让Vue有能力将依赖添加到Watcher中进行管理。

  • 使用索引设置数组的某一项的值,无法被监测到;

  • 修改数组的length属性,不会触发更新;

  • 无法应对MapSet这些集合类型的响应式,需要开发者自己想办法解决。

这些缺点都来自于Object.defineProperty这个API本身的局限性。

Vue3的做法

Vue3中,数据拦截使用了ES6Proxy API,这个API可以直接将目标对象作为整体,拦截对它的各种操作,包括:

  • 对某个属性的读/写;
  • 新增属性;
  • 删除属性;
  • Proxy可以Map/Setgetter拦截到对get/set/add等方法的调用。

因此,Vue3相比于Vue2

  • 解决了递归配置getter&setter的问题;
  • 解决了新增/删除属性没有响应式的问题;
  • 实现了响应式的Map/Set

可以说Vue3在响应式这一部分的提升来自于ES6提供了更现代化更高效的API


编译优化

Vue2中,从new Vue()到生成DOM的过程大致如下:

graph TBA[new Vue] --> B[init]B --> C[$mount]C --> D[compile]D --> E[render]E --> F[vnode]F --> G[patch]G --> H[DOM]

上述的响应式过程发生在init阶段,而template编译为render function的阶段可以在打包过程中完成。

而在运行时中,耗时较多的是patch阶段。

Vue3在编译阶段优化了编译的结果,实现了对patch过程的优化。

具体来说是通过flag标记、静态提升的手段来实现的。

Vue2中,数据更新并触发重新渲染的粒度是组件级的。

在组件内部仍然需要遍历整颗VNode树,如果组件包含许多静态内容,那么diff算法会在静态内容上浪费许多时间。

也就是说diff算法的效率由组件的虚拟DOM树规模决定,而不是由动态节点的规模决定。

Vue3使用了Block Tree来优化diff过程。

Block Tree

Block Tree 是一个将模板基于动态节点指令切割的嵌套区块,每个区块内部的节点结构是固定的STABLE_FLAGMENT)。

对于结构固定的区块,仅需要使用一个Array来追踪其包含的动态节点。

借助 Block Tree,Vue3vnode 的更新性能调整为与动态内容的数量相关

其它

  • Vue3在编译阶段实现了对Slot的编译优化、事件侦听函数的缓存优化;
  • Vue3重写了diff算法。

语法API优化

Vue3在语法上的一个大的变动主要是提供了Composition API,即组合式API。

Vue2中,编写组件本质是在编写一个“包含了描述组件选项的对象”,被称为Options API,即选项式API。

选项式API适合开发小型组件,选项内容一目了然。对于包含多个逻辑关注点的大型组件来说,使用选项式API会导致一个逻辑关注点的代码被分散到不同选项中。

组合式API的好处在于可以将逻辑关注点相关的代码封装到一个函数里。

逻辑复用优化

Vue2中,存在mixins这种逻辑复用的方式。它的缺点在于当一个组件混入多个来源的mixins后,会出现命名冲突和数据来源不清晰的问题。

Vue3中,通过组合式函数解决了这一问题,组合式函数将可复用逻辑封装成函数(按照规范通常以use作为函数名开头),通常是返回一个对象。这是一种更灵活且更稳定的做法,因为:

  • 对于组合式函数来说,可以选择性地向外暴露API;
  • 对于使用地组件来说,解构返回的对象时,可以重命名避免命名冲突。

组合式API的其它好处

  • 更好的类型支持:组合式API都是函数,类型更容易推导,不想选项式API所有的内容都要通过this联系;
  • 组合式API对tree-shaking比较友好,代码也更容易压缩。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/777497.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevOps实践

DevOps 一、DevOps介绍 软件开发最开始是由两个团队组成:开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。这看似两个目标不同的团队需要协同完成一个软件的开发。 在开发团队…

高考结束咯,录取结束咯,通知书下来咯,即将开启大学生活咯!

高考结束咯,录取结束咯,通知书下来咯,即将开启大学生活咯!高考结束咯,自我感觉良好,期待着结果出来 结果高考成绩一出来吓我一大跳,657分,比预想中的高了几十分,哈哈哈哈哈哈但是我最关心的人却考砸了,也不知道是不是我的问题(虽然ta比我高),真是逆天!下面是高考…

LeetCode 1557. Minimum Number of Vertices to Reach All Nodes

原题链接在这里:https://leetcode.com/problems/minimum-number-of-vertices-to-reach-all-nodes/description/ 题目: Given a directed acyclic graph, with n vertices numbered from 0 to n-1, and an array edges where edges[i] = [fromi, toi] represents a directed e…

腾讯的cherry-markdown如何在vue项目中自定义视频播放器?【引入自定义组件版,非普通html】

调研好久没给维护的社区增加新内容了,想到社区的播放器还是浏览器原生的,看着挺丑的,因此我打算给社区的cherry-markdown渲染的markdown文章里的视频样式给改改。首先为了让事情不复杂化,我打算引入西瓜视频播放器(https://h5player.bytedance.com ),它支持的功能挺多的,…

腾讯的cherry-markdown如何在vue项目中自定义视频播放器?

调研好久没给维护的社区增加新内容了,想到社区的播放器还是浏览器原生的,看着挺丑的,因此我打算给社区的cherry-markdown渲染的markdown文章里的视频样式给改改。首先为了让事情不复杂化,我打算引入西瓜视频播放器(https://h5player.bytedance.com ),它支持的功能挺多的,…

LeetCode 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix

原题链接在这里:https://leetcode.com/problems/minimum-number-of-flips-to-convert-binary-matrix-to-zero-matrix/description/ 题目: Given a m x n binary matrix mat. In one step, you can choose one cell and flip it and all the four neighbors of it if they exi…

【安全技术系列】用户实体行为分析(UEBA)

一、背景 数字新时代正在加速全面到来,网络环境变得更加多元、人员变得更复杂、接入方式多种多样,网络边界逐渐模糊甚至消失,同时伴随着企业数据的激增。数字化转型促进组织的业务发展的同时,也带来了重大的网络安全挑战。 1.越来越多的外部攻击,包括被利益驱动或国家驱动…

2024 暑假友谊赛 3

2024 暑假友谊赛 3 A - A CodeForces - 1187E 思路 设 \(f_i\) 表示以 \(i\) 为根的子树产生的贡献,则有 \(f_i=size_i+\sum\limits_{j\in son_i} f_j\),即起初选定 \(i\) 为起点后产生 \(size_i\) 的贡献,后续是它的子树产生的贡献。 但这样以不同根节点去求贡献是 \(O(n^2…

LeetCode 2189. Number of Ways to Build House of Cards

原题链接在这里:https://leetcode.com/problems/number-of-ways-to-build-house-of-cards/description/ 题目: You are given an integer n representing the number of playing cards you have. A house of cards meets the following conditions:A house of cards consists…