Skip to content

权衡的艺术

TIP

Vue.js设计与实现第一篇框架设计概览

第一章 权衡的艺术

1. 命令式与声明式

视图层框架通常分为声明式和命令式,它们各有优缺点


1.1. 命令式

命令式框架的一大特点就是 关注过程,代码本身描述的就是"做事的过程"

早期的jQuery就是典型的声明式

js
/*
1. 获取id为app的div标签
2. 它的文本内容为 hello world
3. 为其添加绑定事件
...
*/

// 以上对应的代码为
$('#app') 						// 获取div
	.text('hello world')// 设置文本内容
	.on('click',()=>{})  // 添加绑定事件

1.2. 声明式

与命令式框架不同,声明式更加关注结果

声明式实际上是封装了命令式的代码实现面向用户的声明式

js
<div @click="()=>{}"> hello world </div>

用Vue.js实现上面命令式的相关功能,可以发现,我们提供的是一个“结果”,具体实现这个“结果”的过程,我们并不关心

实际上,是Vue.js帮我们封装了过程,Vue.js内部实现是一定是命令式的,而暴露给用户的却更加的声明式


2. 性能与可维护性的权衡

TIP

声明式的代码不优与命令式代码的性能

拿上面的例子来说,如果想把div标签的文本内容修改为 hello Vue,用命令式代码实现

js
div.textContent = 'hello Vue' // 直接修改

思考一下,这已经是实现这个功能消耗性能的天花板了,可以看到,理论上,命令式的代码可以做到极致的性能优化,因为我们明确知道哪些发生了变化,只需要做必要修改就行了,但声明式代码不一定能做到这点,因为它描述的是结果

js
// 修改前
<div @click="()=>{}"> hello world </div>

//修改后
<div @click="()=>{}"> hello Vue </div>

对于框架来说,实现最优的更新性能,就是找到前后的差异,只更新变化的地方,所以,声明式完成这次更新的代码依然是

js
div.textContent = 'hello Vue' // 直接修改

2.1 性能对比

更新内容所消耗的性能

命令式消耗性能: 直接修改

声明式消耗性能: 找出差异消耗性能 + 直接修改

当找出差异的性能为0时,声明式与命令式代码的性能相同,但无法做到超越,因为声明式实际上是封装了命令式的代码实现面向用户的声明式

在性能层面上命令式是更好的选择,但Vue.j却选择声明式的设计方案,原因是声明式代码的可维护性更强

可维护性与性能的权衡,在保持可维护性的同时让性能消耗更小

3. 虚拟DOM

前文说到,声明式代码更新消耗性能: 找出差异消耗性能 + 直接修改消耗的性能,如果最小化找出差异消耗性能最小化,那么就能让声明式代码性能无限接近命令式代码性能。

虚拟DOM

最小化找差异消耗的性能 --> 让声明式代码性能无限接近命令式代码性能 ,而虚拟DOM就是为最小化找差异消耗的性能而出现的

理论上: 虚拟DOM更新成操作性能不可能比原生javascript操作DOM更高(DOM层面的计算远比javascript层面的计算性能差),虚拟DOM的主要优势在于局部更新,虚拟DOM在javascript层面的运算要比创建页面时多出一个Diff的性能消耗,但不会产生数量级的差异

3.1. 原生DOM更新页面

重新构建HTML字符串,再重新设置DOM元素的innerHTML属性,也就是说,哪怕只改变一个字,都要重新设置innerHTML属性,相当于是销毁后全部重新创建 消耗性能:渲染HTML字符串 + 销毁所有旧DOM + 新建所有新DOM

3.2. 虚拟DOM更新页面

重新创建新的JS对象(虚拟DOM树),再比较新旧虚拟DOM树,找到变化并更新 消耗性能:创建新的JS对象 + Diff + 必要的DOM更新

4. 运行时和编译时

简单说,运行时是指一段代码,直接扔进浏览器里能运行,编译时是指一段代码不能直接在浏览器里跑,需要先经过编译器编译,再放到浏览器里才能运行

Vue3采用了运行时+编译时架构

Released under the MIT License.