vue技术栈:从设计思想到实现原理

1,607 阅读6分钟

本文是react技术栈:从原理到源码的姊妹篇,也是这篇框架概论的延伸,因此彼此关联比较大,至少建议阅读完框架概论再回来继续。
本文照例会从核心库、状态管理、路由管理三个方面进行讲述

这里的vue-next指的是vue.js 3.0,其他是配套库,本文参考链接大部分是vue官方资料。

本次会对前两章进行讨论,后续会持续更新。

vue设计思想

本部分参考

框架的定位

vue的定位就是尽可能的降低前端开发的门槛,来解决开发中遇到的问题,作为一个小团队的开源项目,并没有react那样的大树好乘凉,因此整个开发的设计思路就是使用当前比较优秀的解决方案,而不是去尝试各种新思路(比如fiber)。
也因为此,vue无论是从使用还是从源码都比react门槛低得多。vue的最终实现是在各种方案中经过权衡(trade-offs)才选择了目前符合自己定位而又不失性能的方案。

不过vue 3.0之后vue从使用者的心智负担、hooks的实现和性能方面来看,比react稍好了一些。

权衡的维度

一个框架需要做很多维度的权衡,这里拿出三个维度来讨论vue的设计

scope

scope指的是一个框架在设计时应该承担哪些职责。

我们常见框架中的两极代表就是react和angular:

其中前者的核心开发团队,只负责react核心库的开发,即只实现了一套基础的ui模型,其他交给生态,可以在此基础上构建出自己的抽象,由于facebook的背景背书,生态发展已经没有问题,但对于用户来说是需要对生态中的各种所谓最佳实践有自己明确的评判标准以便做出选择,否则会无从选择,然后被相对孤立的文档提高了学习门槛。

而后者(包括ember)将整个解决方案一次性提供,会把开发中遇到的问题考虑的比较全面,但带来的是解决方案的固定,不能随着场景调整, 也意味着门槛较高。

而vue结合两者的优点,既能像react一样,按需引入路由和状态管理,又像angular一样提供了完整的解决方案,这就是vue生成的渐进式框架。

render mechanism

render mechanism指的是从代码的组织到运行的机制。

在这个维度又可以分为jsx和template两种写法。

其中前者(比如react)利用动态函数,并以virtual dom为最终渲染的中间表示,好处是灵活度高,且能渲染到dom以外的形式,比如react native,缺点是diff本身很耗性能,由于过于灵活无法做充分的优化且需要比较重的运行时完成调度等工作;

后者(比如svelte,ember)利用模板组织代码,由于格式固定,所以优化较好,而且使用AOT(Ahead-Of-Time - 预先编译)而不需要前者很重的运行时代码,因此当项目较小时输出的生产代码也较少,但是难以发挥js的灵活性,且当项目很大时,每个模板都需要完整的代码,生产代码小的优点并不一定还能成立。

而vue又是结合了两者,既能使用模板来编写,获取它的优化,又提供了jsx方式,在必要时利用它的自由度。

state mechanism

state mechanism指的是状态变化侦测相关的东西,可看之前讨论过的,这里总结一下就是react使用的方式是当一个组件发生状态变化时,会重新diff整个子组件(经过优化后可以跳过某些不必要的diff),而vue会在初次渲染时注入依赖,当状态变化时只需要diff组件界别的virtual dom,当然注入依赖本身也耗费性能。

vue 3.0 的优化

本部分参考

我这里就假设各位对vue2已经比较熟悉,这里会对前不久发布的vue3的变化进行解读,了解一下哪些变化和设计思路。

3.0的优化点主要包含以下,其中核心是更快和增强ts支持


下面对一些细节进行展开

更小

除了部分必须的文件,其余都写成了es module,从而可以被tree shaking

更快

数据变动侦测方法

从使用object.definProperty来劫持getter和setter改为使用Proxy,当我们使用前者时对js对象频繁变化不利于js引擎的优化,而后者是直接提供的代理api,而不改变本来对象。

virtual dom 优化

之前我们讲了virtual dom采用了virtual和template结合的问题,模板在这里只是一种代码组织手法,然后将模板转化为一般的virtual dom,并没有充分利用模板带来的优化空间,新版将模板中可变的部分和静态部分进行分块,这样的每块树被称为block tree。比如v-if或v-for,这样由原来的diff整个组件整体,现在变化diff动态的块,比如下图中动态的只有一个p元素

编译时优化

比如提前将slot编译为函数,减轻父子组件的耦合等。

加强ts的支持

ts中的class api没被引入,因为会导致注入到this中的属性类型声明出现问题,而且引入并不会代来实际的好处,在ui中并不需要传统oop中的继承而更多的是组合,因此在vue3中引入了基于函数的组合式api,类似于react的hooks,但是和hooks的一个重要区别是后者每次组件更新都会调用,而组合式api中因为其中声明的值都是可追踪的,因此setup在组件初始化时只调用一次。

响应式

这部分对响应式原理的细节进行讨论。

事件系统

这里讨论vue内部实现的事件系统

源码

这里会对vue的源码进行分析

状态管理

这里讨论vuex原理及源码

路由管理

这里讨论vue-router原理及源码