vue.js的设计与实现(权衡的的艺术-命令式和声明式)

什么是命令式和声明式呢?

我们来看一下jQuery,他是典型的命令式框架,命令是框架的一大特点就是注重过程

$('#app').text('hello word').on('click',()=>{alert('ok')})

我们可以看到上面这一段代码,做的事情是:获取到id为app的元素,把他的文本内容更改为hello word,并添加了一个点击事件,点击后弹出ok提示

我们再看看声明式的写法(以vue来举例)

<div @click='()=>{alert("ok")}'>hello word</div>

看以上代码,往往声明式的框架关注的是结果。关于这个结果如何实现的,我们并不需要关系,vue.js会帮我们实现。换句话说:vue.js帮我们封装了过程。
因此,我们不难猜出,vue.js内部一定是命令式的,而暴露出来给用户的却更加声明式

性能与可维护性的权衡

在这里我们先抛出一个结论:声明式代码的性能不优于命令式代码的性能

为什么会得出这样的结论呢?很简单我们假设一下,我们要把上面的div的内容要改成 ‘hello vue3’有没有比一下代码性能更好的呢?

div.textContent = 'hello vue3'

答案是没有 为什么呢?

我们现在来思考一下,如果是声明式框架会怎么样,如以下代码

<!-- 之前: -->
<div @click='()=>{alert("ok")}'>hello word</div>
<!-- 之后 -->
<div @click='()=>{alert("ok")}'>hello vue3</div>

这个是他的描述结果,要从之前的word改成vue3,对于框架而言,如果需要实现最优的性能,那一定是找到前后的差异并只更新变化的地方,但最优的更新代码仍然是:

div.textContent = 'hello vue3'

我们把A定义为:直接修改的性能消耗,B定义为:找出差异的性能消耗
那么:

命令式代码的更新性能消耗:A
声明式代码的更新性能消耗:B+A

我们可以看到,声明式代码会比命令式代码多出找出差异部分的性能消耗,最理想的情况就是 B为0(找出差异的性能消耗为0)是,命令式代码和声明式代码的性能消耗相同,但是无法做到超越。毕竟框架本身就是封装了命令式代码才实现了面向用户的声明式

这里就符合我们最开始得到的解困:声明式代码的性能不优于命令式代码的性能

那么,问题又来了,为什么vue.js不选择性能更好的命令式,而选择声明式呢?

问题就在于:声明式代码的可维护性更好,我们通过以上的代码,我们可以明确的感受到:命令式代码,我们需要去维护整个过程,而声明式代码,我们只需要展示结果就可以,看上去更加的直观,至于做事的过程,我们并不需要关系,因为vue.js已经帮我们封装好了。而框架设计者要做的就是把B(找出差异的能量消耗)降低到最小,也就是在保持可维护性的同时让性能损失最小

虚拟DOM的性能到底如何

我们在上面提到了 声明式代码的性能消耗 为 A+B(直接修改的性能 + 找出差异的性能)
如果我们最小化B,那我们声明式代码就无限趋近于命令式代码,这里我们就需要说到vue.js的虚拟DOM

虚拟DOM就是为了最小化找出找出差异最小化出现的

具体的虚拟dom的diff算法 我们在后面再说。其实我们都知道 涉及dom层面的计算远比JavaScript层面的计算差,我们这边就来对比一下虚拟dom和innerHTML的在创建页面时候的性能

虚拟dominnerHTML
纯JavaScript层面的计算创建JavaScript对象(VNode)渲染HTML字符串
DOM层面的计算新建所有的DOM元素新建所有的DOM元素

可以看到在创建页面的时候无论是纯JavaScript层面的计算和dom层面的计算,两者的差距不大。
我们再看看在更新页面的时候

虚拟dominnerHTML
纯JavaScript层面的计算创建新的JavaScript对象 + Diff渲染HTML字符串
DOM层面的计算做必要的dom更新销毁所有旧的dom元素,新建所有新的dom元素

我们可以看到,在更新页面的时候,在纯JavaScript层面的计算要比创建页面的时候多了一个diff的性能消耗。在dom层面的计算,我们可以看到虚拟dom只会做必要的dom更新,但是innerHTML来说,需要全量的更新,这时候虚拟dom的优势就体现出来。

我们在更新页面的时候 加上性能因素

虚拟dominnerHTML
纯JavaScript层面的计算创建新的JavaScript对象 + Diff渲染HTML字符串
DOM层面的计算做必要的dom更新销毁所有旧的dom元素,新建所有新的dom元素
性能因素与数据的变化量相关于模板的大小相关

这张表格的的意思是:虚拟dom的性能因素是diff,在innerHTML的性能问题主要是销毁所有的旧元素,在新建所有新的dom元素,如果模板越大,在dom层面的性能消耗也越大
我们粗略的终结一下 innerHTML、虚拟dom 以及原生 JavaScript(指createElement等方法)在更新页面时的性能


性能差 ——> 性能高

innerHTML(模板)虚拟dom原生JavaScript
心智负担中等心智负担低心智负担高
性能差可维护性高,性能不错可维护性差,性能高

总结

  • 我们先讨论了命令式和声明式的差异,其中命令式更加关注过程,而声明式更加关注结果。命令式在理论上时可以做到性能极致的优化,但是用户需要承受极大的心智负担;而声明式能够有效的减少用户的心智负担,但是性能上有一定的牺牲,框架设计者要想办法尽量的使其性能的损耗最小化
  • 接着我们讨论了虚拟dom的性能,并给出了一个公式,声明式的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗,虚拟dom的意义就在于找到差异的性能最小化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值