这本书主要是从顶层的角度来观察Vue3框架的设计,首先阐述了设计一个框架需要考虑的问题,然后阐述了框架内部各个模块的设计方式。
因为在Vue3模块中,存在各个模块,每个模块都有属于自己的功能的细节,这些模块之间是相互联系的。
第一章、权衡的艺术
设计一个框架是给人使用的,开发框架目的就是更方便,简单的进行写代码。也就是说要让使用者的心智负担要比较小。所以说框架的设计者就要权衡各个方案的优缺点,做到一个平衡。
所以作者讨论了在设计Vue3的时候做的三点权衡。是使用命令式还是声明式,各种方案的性能,是运行时还是编译时。
命令式还是声明式
命令式:即使程序按照我们的写的指令,一条一条的执行,就是命令式。
举个例子:我们要获取页面上的一个盒子,并给这个盒子添加一个文本,然后给盒子添加一个点击事件。
const div = document.querySelector('#app')
div.innerText = 'hello world'
div.addEventListener('click',()=>{alert('点击了div盒子')})
上面代码的步骤是
- 先获取盒子
- 然后给盒子添加文本
- 最后给盒子添加点击事件
可以看到是我们要做什么就按照顺序将要做的用代码一条条写出来,这就是说为的命令式。
声明式: 声明式更加的关注结果。vue就是一个声明式的框架。
下面我们举个例子,在vue中我们要做到和上面一样的效果,只需要一行代码即可。
<div @click = ()=>{alert('点击了div盒子')}>hello world</div>
可以看到在vue中,我们就是提供了一个结果,而这个结果是如何得到的,我们并不关心,这就是声明式代码。
其实声明式的内部就是命令式的代码,换句话说,vue帮我们封装了过程(命令式代码),而暴露给开发者的是结果(就是让开发者可以写声明式代码)
命令式代码和声明式代码的优缺点:前者的性能好于后者,但是后者的代码可维护性强于前者。
因为框架本身就是封装的命令式的代码,才实现了面向用户的声明式,所以说声明式代码的性能是不可以由于命令式的代码的性能。
也就是说声明式的框架,是牺牲了点性能来换取代码的可维护性的。这就是做的第一个权衡,为了提高可维护性而选用了声明式。
关于修改DOM的性能消耗
从上一小节,我们知道vue是声明式的框架,所以说它的性能消耗是比较高的,为了减少性能的消耗,在vue中采用了虚拟DOM的方式。
所以声明式代码的性能 = 找出差异的性能消耗 + 直接修改的性能消耗。
所以说如果我们能最小化的找出差异的性能消耗 (虚拟DOM+diff找出差异), 就是使得声明式代码的性能消耗达到最小。
在js中主要有三种操作DOM的方式。
- innerHTML (有别于document.createElenment 来操作DOM)
- 虚拟DOM
- 原始JS(直接document.createElenment)
作者这里主要对比了使用innerHTML操作页面和虚拟DOM操作页面的性能。
创建页面时的性能
虚拟DOM | innerHTML | |
---|---|---|
js层面的消耗 | 创建JS对象 | 创建 对于的字符串 |
DOM层面的消耗 | 新建所有的DOM | 新建所有的DOM |
可以看到两者的区别不大。
在页面更新的时候的性能
虚拟DOM | innerHTML | |
---|---|---|
js层面的消耗 | Diff+需要更新的JS对象 | 创建一个新的字符串 |
DOM层面的消耗 | 必要的DOM更新 | 销毁全部的DOM 生成全部的新DOM |
可以看到在更新页面的时候,影响虚拟DOM的性能因素与影响innerHTML的性能因素不同。
对于虚拟DOM来说 ,无论页面的大小,性能的消耗之和要更新变化的内容有关
对于innerHTML来说,一点点变化都需要生成和销毁全部的DOM,所以性能的消耗和页面的大小有关,页面越大性能消耗越大。
三种页面更新时候性能消耗的总结:
innerHTML | 虚拟DOM | 原生JS |
---|---|---|
心智负担中 | 心智负担小 | 心智负担大 |
性能差 | 性能中等 | 性能高 |
可维护性强 | 可维护性差 |
综上所述,在维持性能不错的情况下,虚拟DOM可以做到更小的心智负担和更强的代码维护性。
运行时和编译时
首先我们介绍下什么时运行时,什么时编译时。
运行时,就是说用户直接传入虚拟DOM,然后我们通过render(虚拟DOM) 函数进行原始的创建和页面的渲染工作。
编译时,就是说我们直接将树形的HTML 编译成对于的DOM树。(例如:innerHTML的字符串类型的树形结构,我们直接通过compiler进行编译,直接转化为对应的DOM)。
在上文说到vue中采用了虚拟DOM,那vue是运行时的吗?其实不是的,vue是运行时+编译时的。在vue中允许你直接通过h函数传入对应的js对象,然后通过render来构建DOM树。但是其实在大部分时候,我们都不是这样使用的。我们都是直接通过在<template></template>
写对应的HTML结构,其实在vue中,vue使用vue-compiler进行了编译,编译成了虚拟DOM(不是真实DOM),然后再将虚拟DOM通过render进行了声明真实的DOM。
所以说vue是运行时+编译时的。