我们倾向于听到越来越多关于Vue.js即将发布的第3个主要版本的消息。虽然通过跟踪讨论还不能确定一切,但我们可以有把握地认为它将会比当前版本(已经很出色)有很大的改进。Vue团队在改进框架API方面做得非常出色。Evan 你把Vue 3的目标描述为:
- 让它更快
- 缩小一点
- 使其更可维护
- 使其更容易接近原生JS
- 让你的生活更轻松
而我相信,通过看RFC和会谈,上述目标都会顺利实现。在这篇文章中,我想引导大家了解一些我看来最感兴趣的变化,看看它们的影响和可能性。
性能优化
在挖掘某些API之前,作为一个性能狂人,我想先谈谈Vue 3的性能。而且有很多东西可以谈! 我们可以发现几乎每一个面都有明显的改进!
我们先从Vue 3的体积大小说起。
目前,Vue运行时的减压和压缩后的Vue运行时的大小约为20kB(当前2.6.10版本为22.8kB)。Vue 3体积的大小估计只有一半左右,所以只有约10kB!
全局API tree-shaking
在许多其他的优化中,比如更好的模块化,Vue 3的源码将是tree-shakeable。这意味着,如果你不使用它的一些功能(如<keep-alive>组件或v-show指令),它们将不会被包含在你的生产包中。目前,无论我们从Vue core中使用了什么特性,它们都会在我们的生产代码中出现,因为Vue实例是作为一个单一的对象导出的,而bundlers无法检测到这个对象的哪些属性在代码中使用了。
// Vue 2.x - whole `Vue` object is bundled for production
import Vue from 'vue'
Vue.nextTick(() => {})
const obj = Vue.observable({})
为了使全局API tree-shakeable,Vue团队决定通过命名的导出方式导入大部分的API,这样捆绑者就可以检测并删除未使用的代码。
// 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-shakeable的JavaScript API以外,还有很多其他功能。在后台,Vue编译器(将Vue模板转化为渲染函数的工具)会检测到模板中使用的指令,并对其进行 tree-shake。例如下面的模板。
<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])
])
}
每个人都会从全局API tree-shaking 中受益(尤其是我们的用户),但我认为那些做小型、轻量级网站的人,只用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
Proxies的真正影响可以从更快的组件初始化和补丁中看出。根据测试,它的速度大约快了2倍!
这种改进特别重要的原因是,使用getters/setters,Vue必须递归地查看所有的对象和它们的属性并对它们进行转换。而使用代理的时候,这个过程就简单多了。
值得一提的是,通过使用JS Proxies Vue 3将减少对Internet Explorer(不是Edge)的支持,但不用担心–对于那些希望支持IE的用户,将有一个兼容性构建。
时间切片
根据Evan You的推文更新,这个功能不会包含在Vue 3中。
Vue 3的另一个真正令人兴奋但很少被提及的性能功能是实验性的时间切片支持。
我将用一个比喻来解释什么是时间切片。我想让大家想象一下冰淇淋的生产线。很长的队伍,因为那些是城里最好的冰激凌。一个人吃完后,又有另一个,再来一个,再来一个,等等。而且不知道为什么,没有关于可供选择的口味的信息。要想知道这些信息,就需要直接去问卖冰淇淋的大妈。
这种情况下,我们很可能会出现2条线—-一条是给确信要买冰淇淋的人(耐心等待),一条是给想了解更多口味信息的人,然后再决定要不要吃冰淇淋。最新的应该会尽快得到这些信息。可惜的是,只有一位卖冰淇淋的小姐姐,在 “主线 “的客人都还没有上菜之前,她是不会回答任何问题的。
这对于还没有被说服的顾客来说,并不是最好的体验,大部分顾客可能会觉得不值得等待。为了解决这个问题,小姐可以在每服务2-3个客户后回答一个问题。这两个群体应该都很满意这个解决方案。
这正是CPU对Web应用的工作原理。我们有一个 “主线程”(也就是所谓的 “主线程”),它需要完成所有的主要任务(脚本、渲染等),然后才能响应用户的交互。对于某些页面,这可能会导致非常糟糕的用户体验,这取决于你的Vue组件需要多少时间来加载或重新渲染。
为了让它更可靠,最好是将这个脚本评估 “切割 “成块,看看每块之后是否有用户输入需要处理。这样一来,无论需要进行多少次加载或重新渲染,APP都能保持响应速度。这正是Vue 3中的工作方式。
Evan You就是这样介绍Vue 3中的时间分割功能的。注意到脚本执行时间线中的小缝隙了吗,这些缝隙是用来处理用户输入的。
能够轻松识别为什么要对组件进行重新渲染
工具和开箱即用的性能同样重要。根据这一点,我们可以看到Vue 3中出现了一个新的生命周期挂钩–renderTriggered。我们可以用它来跟踪和消除不必要的组件重渲染,当我们将其与时间切片结合起来,这在运行时性能优化中是一个非常强大的武器。
const Component = {
// other properties
renderTriggered (event) {
console.log(`Re-render of ` + this.$options.name + ` component`, event)
}
}
还有什么
在Vue 3中,除了上面提到的内容之外,还有更多,但这些可能是影响最大的改动。大部分未提及的改进都隐藏在Vue编译器生成的代码中,或者说是与实现细节和算法有关。
不过有几个值得一提的改进。
- 输出代码将更容易为JavaScript编译器进行优化
- 输出的代码一般会有更好的优化
- 由于修补算法的改进,将避免不必要的父/子重现
另外,在接下来的日子里,你可以期待Evan You的一篇深度文章,介绍他们专门为Vue编译器做的性能优化(一旦发布,我将在文章中添加链接)。
总结
尽管Vue已经被公认为是目前性能最好的框架之一,但在第3版中,我们将看到它的重大改进。尤其是在它的包大小和运行时性能方面。同时也有无数的微观优化。我认为Vue 3非常适合现代移动优先和性能导向的web。
不要忘记,Vue是唯一一个完全由社区驱动的主要框架。这篇文章中列出的所有改动(还有更多)都是以RFC的形式与社区一起讨论的。你可以帮助核心团队,对活跃的RFC发表你的意见,甚至提出你自己的改进建议。让我们一起让Vue变得更好 ?。
接下来是什么?
在下一篇文章中,我们将探讨新的Vue 3 API将如何影响我们编写Web应用的方式。我们将看看各种API,包括最近流行的Component API,并看看我们如何利用它来写出更好、更可维护的代码。
原文:https://vueschool.io/articles/vuejs-tutorials/faster-web-applications-with-vue-3/
译文:https://qdkfweb.cn/vue3-faster.html