使用Vue 3更快的Web应用程序
即将发布的Vue.js的第三个主要版本。
通过下面的讨论,虽然还不能确定所有内容,但是我们可以放心地认为,它将是对当前版本(已经非常出色)的巨大改进。Vue团队在改进框架API方面做得非常出色。Evan You将Vue 3的目标描述为:
让它更快
让它更小
使它更易于维护
使原生目标更容易
让您的生活更轻松
通过查看RFC,我确信上述所有目标都将毫无问题地实现。在本文中,我将引导您完成一些对我来说最有趣的更改,这些更改对我的影响和可能性而言。
性能优化
在探究某些API之前,作为性能怪胎,我想谈一谈Vue 3的性能。还有很多事情要讨论!我们几乎可以在每个表面上找到明显的改进!
让我们从Vue 3的捆绑包大小开始。
当前最小化和压缩的Vue运行时权重约为20kB(当前2.6.10版本为22.8kB)。Vue 3捆绑包估计重约一半,因此只有〜10kB!
全局API分块(Tree Shake机制)
诸如更好的模块化之类的许多其他优化之上,Vue 3源代码将加入tree-shake。这意味着,如果您不使用其某些功能(例如component
或者v-show
指令),它们将不会包含在您的基础包中。
当前,无论我们从Vue核心使用什么功能,它们最终都会出现在生产代码中,因为Vue实例被导出为单个对象,并且捆绑程序无法检测到该对象的哪些属性在代码中使用。
// Vue 2.x - whole `Vue` object is bundled for production import Vue from 'vue' Vue.nextTick(() => {}) const obj = Vue.observable({})
为了使全局API可以进行代码分块,Vue团队决定通过命名导出导入其中的大多数方法,以便捆绑程序可以检测和删除未使用的代码:
// Vue 3.x - only imported properties are bundled import { nextTick, observable } from 'vue' nextTick(() => {}) const obj = observable({})
这是一个重大变化,因为以前的全局API现在只能通过命名的导出才能使用。此更改影响:
Vue.nextTick
Vue.observable
Vue.version
Vue.compile
(仅完整版本)Vue.set
(仅在2.x兼容版本中,您很快会找到原因)Vue.delete
(同上)
我们需要一段时间才能完全受益于此功能,因为它需要在生态系统中采用。Vue团队将发布兼容性版本,因此我们应该能够使用也使用旧API的插件,但会降低性能。
除了tree shake的JavaScript API以外,还有很多其他功能。在后台,Vue编译器(将Vue模板转换为呈现功能的工具)将检测模板中使用的指令,并对其进行树状摇动。例如下面的模板:
<transition> <div v-show="ok">hello</div> </transition>
在被Vue编译器处理后,看起来或多或少是这样的:
import { h, Transition, applyDirectives, vShow } from 'vue' export function render() { return h(Transition, [ applyDirectives(h('div', 'hello'), this, [vShow, this.ok]) ]) }
每个人都会从Global API tree shake中受益(尤其是我们的用户),但是我认为制作小型轻量级网站,比如:仅使用Vue功能子集进行交互的人(最能替代jQuery之类的库)的人。
基于代理的响应式机制
捆绑包的大小可能会严重影响您的应用加载时间,但是下载后,捆绑包的大小也应能够快速呈现且运行流畅。
Vue核心团队非常了解这一点,这就是为什么我们在运行时性能上也有很大改进的原因。
让我们从基于JavaScript Proxies的最具影响力的新反应系统之一开始。当前的Vue反应系统是基于的Object.defineProperty
,这有一些限制。最常见和令人沮丧的一个事实是Vue 无法跟踪反应对象的属性添加/删除。为此,我们需要使用Vue.set
并Vue.delete
保持反应系统正常运行。使用JS Proxies,我们终于可以摆脱这种丑陋的解决方法。
// Adding a new property to reacitve object in Vue 2.x Vue.set(this.myObject, key, value) // Adding a new property to reactive object in Vue 3 this.myObject[key] = value
代理的真正影响可以从更快的组件初始化和修补中看出。根据测试,速度大约快2倍!
由于以下事实,这种改进的原因尤为重要,那就是Vue必须使用吸气剂/设置剂来递归地遍历所有对象及其属性并对其进行转换。使用代理,此过程变得容易得多。
值得一提的是,使用JS Proxies Vue 3会放弃对Internet Explorer(不是Edge)的支持,但是请不要担心-对于希望支持IE的用户来说,将会建立兼容的版本。
时间分片
根据Evan You的推文更新此功能不会包含在Vue 3中。
Vue 3的另一个真正令人兴奋但很少提及的性能功能是对时间切片的实验支持。
我将用一个隐喻来解释什么是时间切片,我想让你想象一条冰淇淋生产线,很长的一个,因为那是镇上最好的冰淇淋。提供一个人之后,就会出现另一个人,等等。由于某种原因,没有关于可用口味的信息。要获取此信息,您需要询问直接出售冰淇淋的女士。
在这种情况下,我们可能最终会得到2条记录-其中一条给确信要购买冰淇淋的人(耐心等待),另一条给希望了解有关口味的更多信息的人,然后再决定是否要购买冰淇淋或不,最新的应该尽快获得此信息。不幸的是,只有一位女士在卖冰淇淋,她在为“主”线上的所有客户提供服务之前不会回答任何问题。
对于尚未被说服的客户来说,这并不是最好的体验,他们中的大多数人可能会发现不值得等待。为了解决这个问题,这位女士可以每2-3个服务对象回答一次问题。两组都应该对此解决方案感到满意。
这正是CPU与Web应用程序一起工作的方式。我们有一条“主”行(称为“主线程”),需要完成其所有主要任务(脚本,渲染等),然后才能响应用户交互。对于某些页面,这可能会导致非常糟糕的用户体验,具体取决于Vue组件加载或重新呈现所需的时间。
为了使其更可靠,最好将此脚本评估“切割”成碎片,然后查看每个脚本之后是否有要处理的用户输入。这样,无论需要进行多少次渲染或重新渲染,应用程序都将保持响应状态。这就是在Vue 3中的工作方式。
这是Evan在Vue 3中展示时间分片功能的方式。请注意脚本执行时间轴中的小间隙,这些间隙旨在处理用户输入。
能够轻松识别为什么重新渲染组件
工具与开箱即用的性能同等重要。
据此,我们可以在Vue 3中看到一个新的生命周期挂钩-renderTriggered
。我们可以使用它来跟踪和消除不必要的组件重新渲染,当将其与Time Slicing结合使用时,这是在运行时性能优化中非常强大的武器。
const Component = { // other properties renderTriggered (event) { console.log(`Re-render of ` + this.$options.name + ` component`, event) } }
还有什么
除了上面在Vue 3中看到的内容以外,还有很多内容,但是这些可能是影响最大的更改。大多数未提及的改进将隐藏在Vue编译器生成的代码中,或者与实现细节和算法绑定在一起
不过,有几项改进值得一提:
输出代码将更易于针对JavaScript编译器进行优化
输出代码通常会更好地进行优化
由于改进了补丁算法,可以避免不必要的父母/孩子重新渲染
另外,在接下来的几天里,您可以期待Evan You撰写的一篇深入的文章,介绍他们专门针对Vue编译器进行的性能优化(一旦发布,我将使用链接更新该文章)。
摘要
尽管Vue已经确立为目前性能最佳的框架之一,但我们仍将在第三版中看到重大改进。特别是在捆绑包大小和运行时性能方面,还进行了无数次微优化。我认为Vue 3非常适合现代移动优先和性能导向的网络。
不要忘记Vue是唯一由社区完全驱动的主要框架。这篇文章(以及更多)中列出的所有变化都在RFC社区讨论。您可以帮助核心团队,表达您对有效RFC的意见,甚至可以提出自己的改进建议。让我们一起让Vue更好。
下一步是什么
在下一篇文章中,我们将探讨新的Vue 3 API将如何影响我们编写Web应用程序的方式。我们将研究各种API,包括最近流行的Composition API,并了解如何使用它编写更好和更可维护的代码。
原文:Exciting new features in Vue 3
========
本文转载于toimc前端技术,致力于打造前端知识,前端全栈知识,前端知识体系等前端前沿知识的社区平台,激励大家相互学习,共同进步。