"Vue3源码我读过了,我再看书也没用了",这就是我之前的真实写照.再被朋友一顿洗脑过后我开始了500多页的《Vue.js设计与实现》征服之旅.
每一章节都是非常有意思,也都站在了作者和框架设计师的角度去思考设计是否合理以及设计思想是什么?要去解决什么问题?在这里面我也看到了Vue3框架不为人知的一面,而且作者的文笔也是十分有趣,生动的例子以及详细源码解读对于新手阅读源码有着更好地帮助以及理解.
第一章.(权衡的艺术)
第一篇主要是围绕着设计框架者需要考虑的因素,比如是用声明式代码还是命令式?如何在保持可维护性的同时让性能损失最小化?虚拟DOM的性能对比?
众所周知Vue.js框架就是一个声明式框架这点用过Vue的用户我相信都不陌生,但是命令式明明性能要比声明式的好,为什么要采用声明式呢?
这就不得不提声明式代码的可维护性了,我不需要去维护实现目标的整个过程,包括要手动完成DOM的元素的创建,更新,删除等工作.而声明式代码展示的就是我们要的结果至于过程也已经由Vue.js给我们封装好了,这样我们就得出结论,Vue.js底层依旧是使用命令式代码封装的框架但是面向用户的是声明式. 在Vue.js设计与实现这本书书中也提出一个公式假设直接修改的性能消耗为A,找出差异的性能消耗为B,那么:
声明式框架的性能消耗=A + B
命令式框架的性能消耗=A
由此公式就可以看出来其实声明式框架的性能消耗比命令式框架的性能多出找出差异的性能消耗,但是如果我们能想办法让找出差异的性能消耗最小化呢? 由此虚拟DOM顺势而生.
创建虚拟DOM分为两步,第一步创建JavaScript对象,第二步通过递归遍历虚拟DOM树并创建真实DOM.我们同样可以由一个公式来表达虚拟DOM的性能消耗=创建JavaScript对象(VNode)计算量+创建真实DOM的计算量
图片更加直观的让大家看到了innerHTML和虚拟DOM的性能对比
如果同在一个数量级其实两者是并没有任何区别的,性能消耗几乎一样,但是如果是更新呢?请图!
innerHTML需要重新构建HTML字符串再重新设计DOM元素,也就是说如果有一个文字更改了那么所有旧的DOM元素都会被销毁,在全量创建新的DOM元素.而虚拟DOM则是通过Diff算法找出最小差异化,只会找出差异元素并更新.Diff算法不用太过在意,它也是JavaScript层面的运算,所以不会产生数量级的差异.
虽然虚拟DOM的性能比不上极致优化的原生JavaScript但是在保证心智负担和可维护性的前提下相当不错
运行时? 编译时?
首先我们要搞懂什么是运行时什么是编译时?比如:提供一个 render 函数,接收两个参数,一个是具有一定规范的树型结构的数据对象,一个是要挂载的节点。
开发者把树型结构的数据对象传入 render 函数,然后 render 函数根据该对象递归地将数据渲染成 DOM 元素。
这个树型结构须按照一定的规范,形状如下:
接下来我们实现一下Render函数
这种使用纯 JS 的方式生成页面内容就是运行时框架,很显然,在开发者层面,通过这种方式书写代码一定会非常痛苦。
所以在 Vue 里面,我们写的不是类似上文的代码,而是写 template 模板。但是大家也都知道浏览器并不认识tempalte模板,所以你写了一个叫做Compiler的程序他的作用就是把HTML字符串编译成树型结构的数据对象.但是你又想到那我的用户该怎么去使用呢?于是你让用户调用Compiler函数和render函数 此时框架就是运行时和编译时的框架.
由此,我们可以得出结论,Vue 是一个运行时 + 编译时的框架,在编译时把浏览器看不懂的代码转化为 JS 代码,在运行时创建虚拟 DOM,做 diff 对比,更新真实 DOM 等等操作。
举一些实例,比如 jQuery,就是一个运行时框架;Vue ,就比较折中,是运行时 + 编译时框架;而 Svelte,就是一个编译时框架,但是它的真实性能可能达不到理论高度。但是Vue3的编译优化相关内容时,你会看到Vue3在保留运行时的情况下,其性能甚至不输纯编译时的框架.
这一章节主要作者从各个角度分析框架设计者在设计框架时做的哪些权衡,接下来我也会一直更新Vue.js设计与实现各个章节以及会掺杂的个人理解,如果有不同的意见的可以在评论区评论,也希望能够给你带来帮助.