4

-w949

还有几个月距离vue2的首次发布就满3年了,而vue的作者尤雨溪也在去年年末发布了关于vue3.0的计划,如果不出意外,我们将在今年的某个时间点见证Vue3.0的发布,虽然前几天在《StateOfJS: 2018年JavaScript生态圈趋势报告》一文中我们看到目前Vue的使用者比React还少了不少,但在Github上Vue的star数已经超越React,可见用户对Vue的喜爱,那即将发布的Vue3又有什么新特性呢?我们一起来看看吧!

Vue 3.0 已经在原型设计阶段了,而且我们已经实现了一个与 2.0 的特性近乎相等的运行时了。下文中列出的许多条目,要么已经实现了,要么已经确认可实现。那些还未实现或者仍在探索阶段的条目会用一个“*”标记

-w1159

性能提升

一句话简介:更小巧,更快速;支持摇树优化;支持 Fragments 和跨组件渲染;支持自定义渲染器。
  • 更小巧:这份新的代码库在设计之初就考虑到了对“摇树优化 (tree-shaking)”的友好。那些如内置组件 (<transition><keep-alive>) 、运行时工具性指令(v-model)等特性将变为按需导入,所以也是“可摇树的”。对于这个新的运行时,它的大小将永远保持在 10kb 之下。另外,使这些特性变为“可摇树的”后,我们就可以提供更多的内置特性,同时还不会增加网络负载——如果没使用到这些特性的话。

摇树优化,是一种在打包时去除没用到的代码的优化手段,谷歌有一篇教程可以了解下: Reduce JavaScript Payloads with Tree Shaking

  • 更快:在前期的基准测试中,我们看到整体性能有了一倍的提升,包括虚拟DOM的挂载和打补丁(patching,指更新——译注) 的速度(我们从 Inferno 那里学了好些个技巧过来——Inferno 是目前速度最快的虚拟DOM实现),以及组件实例化速度和数据监测的性能。在 3.0 中,你应用的启动时间将缩减一半。
  • 支持 Fragments 和 Portal:虽然体积更小了,但 3.0 还将内置对 Fragments (即允许组件拥有多个根节点) 和 Portal (即允许在 DOM 的其他位置进行渲染,而不是组件内部) 的支持。

关于 Portal ,你可以将其理解为跨组件渲染或者异地渲染,vue-portal 是一个第三方实现,可以了解一下;Fragments 特性也有一个第三方库,但译者认为这个库的内部实现不够完善,叫做 vue-fragments,感兴趣可以了解一下。

  • 增强的 slot 机制:所有由编译器生成的 slot 都将是函数形式,并且在子组件的 render 函数被调用过程中才被调用 (译注:现在只有 scoped slot 才是函数形式,其渲染的时机也是在父组件的渲染进行时)。这使得 slot 中的依赖项 (即数据——译注) 将被作为子组件的依赖项,而不是现在的父组件;从而意味着:1)当 slot 的内容发生变动时,只有子组件会被重新渲染;2)当父组件重新渲染时,如果子组件的内容未发生变动,子组件就没必要重新渲染。这种机制的改变,可以提供更精确的变动探测,也就可以消除没必要的重渲染。
  • 支持自定义渲染器 (Renderer):这个 API 可以用来创建自定义的渲染器,它将作为“一等公民”出现,到时不再需要 fork 一份 Vue 的代码来通过修改实现自定义。这个 API 的到来,将使得那些如 Weex 和 NativeScript 的“渲染为原生应用”的项目保持与 Vue 的同步更新变得更加容易。除此之外,还将使得那些为了各种用途而创建自定义渲染器变得极其容易。

编译器相关的提升 *

  • 如果采用的是支持“摇树优化”的打包器,模板中使用到的那些可选特性,在生成的代码中将通过 ES 的模块语法导入;而在打包后的文件中,那些没用到的可选特性就会被“摇掉”。
  • 由于新的虚拟 DOM 实现所带来的提升,我们可以执行一些更加高效的编译耗时优化,如静态树提升(static tree hoisting)、静态属性提升(static props hoisting);以及为运行时提供一些来自编译器的提示,以此避开子组件的规范过程 (children normalization);提供 VNode 快速创建路径; 等等。
  • 我们计划对解析器进行重写,以便在对模板进行编译发生错误时,可以提供错误发生的位置信息;除此之外还可以带来对模板的 source map 支持;还可以支持第三方工具如 eslint-plugin-vue 和 IDE 的语言服务 (language services) 特性。

API 变动

一句话介绍:除渲染函数 API 和 scoped-slot 语法之外,其余均保持不变或者将通过另外构建一个兼容包来兼容 2.x。
  • 模板语法的 99% 将保持不变。除了 scoped slot 语法可能会有一些微调之外,我们还没有任何其他针对模板的变动计划。
  • 3.0 版本将原生地支持基于 class 的组件,而且无需借助任何编译及各种 stage 阶段的特性,以此提供良好的编写体验。许多现有的 (组件) 配置项将有对应的合理的 class 版本的 API。各种 stage 阶段的特性,如 class 的静态字段和装饰器 (decorator) 等仍然可以选择性地使用,以此增强编写体验。另外,整体的 API 在设计时也将考虑 TypeScript 的类型推断特性。3.x 的代码库本身将用 TypeScript 来编写,并提供增强的 TypeScript 支持。(就是说,TypeScript 的使用与否仍然是整体可选的)
  • 2.x 系列的基于对象的组件格式仍将受支持,不过会在内部将其转换为一个相应的 class。
  • 仍然支持 Mixins。*
  • 为了避免在安装插件时造成对 Vue 的运行时的修改,顶层 API 可能会做一个大的翻修。到时,插件的作用域将只局限到具体的一个组件树,使得对那些依赖于某些具体插件的组件的测试变得容易,也会使得在同一个页面中挂载多个使用不同插件——但使用同一个 Vue 运行时——的 Vue 应用变为可能。*
  • 函数式组件将支持纯函数的书写形式——不过,这样的话异步组件就需要通过一个辅助性函数来显式地创建了。
  • 变动最大的部分将是渲染函数 (render) 中的虚拟DOM的格式。我们现在正在收集主流的第三方库的作者们的反馈,在对这些变动有了更多的信心之后,我们还会将更多的细节曝光;虽然变动较大,但是只要你没在你的应用中重度使用手写的渲染函数 (不是指 JSX),那么变动之后的升级应该会比较容易。

代码重构

一句话介绍:更优良的内部模块解耦;TypeScript;更易于贡献的代码库。

在从零开始编写 3.0 之初,“达到更加清晰和更易维护的架构,特别是为了让代码的贡献变得容易”就是我们的目标。为了对复杂性进行隔离,我们将一些内部功能拆分为了多个单独的包。例如,observer 模块将成为一个单独的包,拥有自己对外的 API 和自己的测试用例;不过请注意,这不会对框架级的 API 造成影响——你不需要另外手动从多个包里导入许多小件小件的模块就可以使用 Vue,相反 Vue 的最终包会事先装配好这些内部包。

另外,代码库现在改为了用 TypeScript 编写;虽然这会使得“熟练TypeScript”成为对新代码库进行贡献的一个前置要求,不过我们相信有类型信息配合 IDE 的支持,对于一个新的贡献者来说,要做出有意义的贡献,实际上反而会更加容易。

将 observer 和 scheduler 解耦为分开的两个包后,我们还可以拿一些替代的实现对这两个包进行置换试验。例如,我们可以实现一个兼容 IE11、API 也相同的 observer;或者实现另外一种利用 requestIdleCallback 来在长耗时的更新中产出工作成果到浏览器的 scheduler。

重写虚拟DOM (Virtual DOM Rewrite)

随着虚拟 DOM 重写,我们可以期待更多的 编译时(compile-time)提示来减少 运行时(runtime)开销。重写将包括更有效的代码来创建虚拟节点。

优化插槽生成(Optimized Slots Generation)

在当前的 Vue 版本中,当父组件重新渲染时,其子组件也必须重新渲染(11月20日更新:这句话是不严谨的,非常容易产生误导,我觉得有必要说明一下: 2.0 组件的重新渲染就是组件粒度的,除非修改的数据是子组件的 props,才会触发子组件的重新渲染。引用自:https://juejin.im/pin/5bf28dd...)。 使用 Vue 3 ,可以单独重新渲染父组件和子组件。

静态树提升(Static Tree Hoisting)

使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态组件,然后将其提升,从而降低了渲染成本。它将能够跳过未整个树结构打补丁的过程。

静态属性提升(Static Props Hoisting)

此外,我们可以期待静态属性提升,其中 Vue 3 将跳过不会改变节点的打补丁过程。

基于 Proxy 的观察者机制

目前,Vue 的反应系统是使用 Object.defineProperty 的 getter 和 setter。 但是,Vue 3 将使用 ES2015 Proxy 作为其观察者机制。 这消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。

为了继续支持 IE11,Vue 3 将发布一个支持旧观察者机制和新 Proxy 版本的构建。

兼容 IE 11 *

一句话介绍:IE 11 将受到支持,但将会是另外构建一个版本 (build) 的形式支持,不过这个版本会存在与 Vue 2.x 响应式机制所存在的同样的局限。

新的代码库目前只针对主流浏览器,而且我们假定他们都支持 ES2015。但是,哎,我们也知道在可预见的未来还有很多用户仍然需要支持 IE11。除了 Proxy 外,大多数 ES2015 的特性都可以用转译或者垫片的方式在 IE11 中使用。我们的计划是另外单独实现一个具有同样 API 的替代性 observer,不过是基于老式的 Object.defineProperty API;然后再通过单独构建一个使用这个实现的 Vue 3.x 版本 (build) 进行发布,不过这个单独的版本还是会有 Vue 2.x 在变动探测方面所存在的问题,所以它其实并不是一个完全兼容 3.x 的一个版本。我们也意识到这会给第三方库的作者们带来某些不便,因为他们需要考虑两个不同版本之间的兼容性问题,不过当我们真的推进到那个阶段时,那时我们肯定会确保提供一份清晰的指导。

监测机制

一句话介绍:更加全面、精准、高效;更具可调试性的响应跟踪;以及可用来创建响应式对象的 API。

3.0 将带来一个基于 Proxy 的 observer 实现,它可以提供覆盖语言 (JavaScript——译注) 全范围的响应式能力,消除了当前 Vue 2 系列中基于 Object.defineProperty 所存在的一些局限,如:

  • 对属性的添加、删除动作的监测
  • 对数组基于下标的修改、对于 .length 修改的监测
  • 对 Map、Set、WeakMap 和 WeakSet 的支持

另外这个新的 observer 还有以下特性:

  • 公开的用于创建 observable (即响应式对象——译注) 的 API。这为小型到中型的应用提供了一种轻量级的、极其简单的跨组件状态管理解决方案。(译注:在这之前我们可以通过另外 new Vue({data : {...}}) 来创建这里所谓的 observable;另外,其实 vuex 内部也是用这种方式来实现的)
  • 默认为惰性监测(Lazy Observation)。在 2.x 版本中,任何响应式数据,不管它的大小如何,都会在启动的时候被监测。如果你的数据量很大的话,在应用启动的时候,这就可能造成可观的性能消耗。而在 3.x 版本中,只有应用的初始可见部分所用到的数据会被监测,更不用说这种监测方案本身其实也是更加快的。
  • 更精准的变动通知。举个例子:在 2.x 系列中,通过 Vue.set 强制添加一个新的属性,将导致所有依赖于这个对象的 watch 函数都会被执行一次;而在 3.x 中,只有依赖于这个具体属性的 watch 函数会被通知到。
  • 不可变监测对象(Immutable observable):我们可以创建一个对象的“不可变”版本,以此来阻止对他的修改——包括他的嵌套属性,除非系统内部临时解除了这个限制。这种机制可以用来冻结传递到组件属性上的对象和处在 mutation 范围外的 Vuex 状态树。
  • 更良好的可调试能力:通过使用新增的 renderTracked 和 renderTriggered 钩子,我们可以精确地追踪到一个组件发生重渲染的触发时机和完成时机,及其原因。

发布时间

不必太过担心,至少还能缓半年。

参考来源:
Plans for the Next Iteration of Vue.js
[[译] 尤雨溪:Vue 3.0 计划](https://juejin.im/post/5bb719...

周小肆
6.1k 声望2.9k 粉丝