阅读《Vue.js设计与实现》总结

第一章:权衡的艺术

在这一章中,开头的一句话,描述了框架设计的精髓,这句话也是尤雨溪在多个开发者大会中经常提到的,那就是:框架的设计,本身就是一种权衡的艺术。

在本章中,我们首先讨论了命令式声明式这两种范式的差异,其中命令式更加关注过程,而声明式更加关注结果。命令式理论上可以做到极致优化,但是用户要承受巨大的心智负担;而声明式能够有效减轻用户的心智负担,但是性能上有一定的牺牲,框架设计者要想办法尽量使性能损耗最小化。

接着讨论了虚拟DOM的性能,并给出了一个公式:声明式的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗虚拟DOM的意义就在于使找出差异的性能消耗最小化。对比虚拟DOM原生JavaScriptinnerHTML三者操作页面的性能。发现与页面大小变更部分的大小都有关系,除此之外,还与是创建页面还是更新页面也有关系。最后发现虚拟DOM是个不错的选择。

最后,介绍了运行时、编译时的相关知识,了解纯运行时、纯编译时以及两者都支持的框架各有什么特点,并总结出Vue.js3是一个编译时+运行时的框架,它在保持灵活性的基础上,还能通过编译手段分析用户提供的内容,从而进一步提升性能

在这一章中,书中分别从三个方面来去分析了所谓权衡的艺术,到底是什么意思。

命令式和声明式

所谓命令式指的就是:关注过程的范式。而声明式指的就是:关注结果的范式。

张三的妈妈,让张三去买酱油。
那么对于张三而言,他就需要:拿钱、出门、下楼、进超市、拿酱油、付钱、回家。
而对于张三的妈妈来说,她完全不需要关心张三做了什么,只需要对张三说一声就可以了。

那么在这个例子中,张三就是一个典型的命令式,他需要完成整件事情的所有过程。

而张三的妈妈,就是典型的声明式,她不关心过程只关心结果。

那么这里大家来想一下,vue 是声明式的?还是命令式的?

对于 vue 而言,它的内部实现一定是 命令式 的,而我们在使用 vue 的时候,则是通过 声明式 来使用的。

也就是说: vue 封装了命令式的过程,对外暴露出了声明式的结果

性能与可维护性的权衡

在明确好了命令式和声明式的概念之后。接下来咱们来看下从 性能 层面,vue 所体现出来的一种权衡的方式。

针对于性能的分析,主要从两个方面去说。

首先第一个方面:大家觉得 是命令式的性能更强,还是声明式的性能更强呢?

答案是:命令式的性能 > 声明式的性能。

其实原因非常简单,对于 命令式 的代码而言,它直接通过 原生的 JavaScript 进行实现,这是最简单的代码,没有比这个更简单的了,我们把它的性能比作1

而声明式,无论内部做了什么,它想要实现同样的功能,内部必然要实现同样的命令式代码。所以它的性能消耗一定是 1 + N 的。

那么既然如此,vue 为什么还要对外暴露出声明式的接口呢?

这其实是因为:声明式的可维护性,要远远大于命令式的可维护性。

命令式代码:

1
2
3
const div = document.querySelector('#app')
div.innerHTML = 'hello world'
<span style="color: green">+</span> div.addEventListener('click', () => alert('ok'))

声明式代码:

1
<div @click="() => alert('ok')">hello world</div>

从这两段代码(声明式和命令式代码)中就可以发现,声明式代码比命令式代码要简单的多。

越简单的代码,可维护性就越强。

当性能与可维护性产生冲突的时候,那么舍鱼而取熊掌者也。(注意:在vue的性能优化之下,它并不会比纯命令式的性能差太多)

而这样的一种权衡,在template模板中,更是体现的淋漓尽致。

在前端领域,想要使用JavaScript修改html的方式,主要有三种:原生JavaScriptinnerHTML虚拟DOM

很多人认为虚拟DOM的性能是最高的,其实不然。我们来看一下对比:

心智负担:虚拟DOM < innerHTML < 原生JavaScript
性能:innerHTML < 虚拟DOM < 原生JavaScript
可维护性:原生JavaScript < innerHTML < 虚拟DOM

从这个对比我们可以发现,虚拟 DOM 的性能,并不是最高的。

但是它的 心智负担(书写难度)最小, 从而带来了 可维护性最高。所以哪怕它的性能并不是最高的。vue 依然选择了 虚拟 DOM 来进行了渲染层的构建。

这个也是一种性能与可维护性的权衡。

运行时和编译时

第一章的最后一部分,主要讲解的就是 运行时编译时

这两个名词,各位小伙伴在日常开发中,应该是经常听到的。

它们两个都是框架设计的一种方式,可单独出现,也可组合使用。

那么下面咱们就分别来介绍一下它们。

首先是 运行时runtime

它指的是利用render函数,直接把虚拟DOM转化为真实DOM元素的一种方式。 在整个过程中,不包含编译的过程,所以无法分析用户提供的内容。

其次是编译时compiler

它指的是:直接把template模板中的内容,转化为真实DOM元素。因为存在编译的过程,所以可以分析用户提供的内容。同时,没有运行时理论上性能会更好。目前该方式,有具体的实现库,那就是现在也非常火的Svelte。但是这里要注意的是,它的真实性能,没有办法达到理论数据

最后是运行时 + 编译时

它的过程被分为两步:
1.先把template模板转化为render函数。也就是编译时
2.再利用render函数,把虚拟DOM转化为真实DOM.也就是运行时
两者的结合,可以在编译时,分析用户提供的内容,在运行时,提供足够的灵活性
这也是vue的主要实现方式