前言
从范式角度来看,视图层框架通常分为命令式和声明式。作为框架设计者,应该对两种范式都有足够的认知,才能做出正确的选择,甚至想办法汲取两者的优点并将其捏合。
那么Vue3框架应该设计成命令式还是声明式?这两种范式有何优缺点?我们能否汲取两者的优点?
概念
命令式
早年间流行的jQuery是典型的命令式框架。命令式框架的一大特点是关注过程。
举个例子,我们要做到下面的步骤:
- 获取id为app的div标签
- 它的文本内容为hello world
- 为其绑定点击事件
- 当点击时弹出提示:ok
那么,如果是用jQuery这种命令式框架实现,那么代码就是:
$('#app') .text('hello world') .on('click', ()=>{ alert('ok') }) 复制代码
可见,每一行代码跟我们的需求描述是一一对应的,自然语言描述能够与代码产生一一对应的关系,代码本身描述的是“做事的过程”,这符合我们的逻辑直觉。
声明式
声明式框架更加关注结果。 上面的例子,我们改用vue:
<div @click="()=>aalert('ok')>hello world</div> 复制代码
框架提供的是一个“结果”,上面就像是告诉vue:“嘿,我要一个div,文本内容是hello world,它有个事件绑定,你搞定它。”,至于实现该“结果”的过程,则是由vue完成的,换句话说,就是vue帮我们封装了过程。
因此,Vuejs的内部实现一定是命令式的,而暴露给用户的却更加声明式。
性能与可维护性的权衡
命令式和声明式各有优缺点,在框架设计方面,则体现在性能与可维护性之间的权衡。
先抛出结论:声明式代码的性能不优于命令式代码的性能。
拿上面的例子来说,我们现在需要修改div的文本内容,那么对于命令式代码来说,实现如下:
div.textConent='hello vue' 复制代码
因为我们明确知道哪些发生了变更,只做必要的修改就行。
但如果换做声明式,因为它描述的是结果,就不一定能做到这一点。对于框架来说,为了实现最优的更新性能,它需要找到前后的差异并只更新变化的地方,但是最终完成这次更新的代码依然是:
div.textConent='hello vue' 复制代码
所以对于声明式来说,会多了一个步骤:查找前后差异并找出需要更新变化的地方。换句话说,声明式代码比命令式代码多出查找差异的性能消耗,最理想的情况是,当找出差异的性能消耗为0时,声明式与命令式代码的的性能相同,但是无法做到超越。
那么为什么要选择声明式的设计方案?
原因在于声明式代码的可维护性更强。
从上面的例子来说,采用命令式代码开发,需要维护实现目标的整个过程,包括要手动完成DOM元素的创建、更新、删除等工作。而声明式代码展示的就是我们要的结果,看上去更直观,关于做事的过程,我们不需要care。
这就体现了架构设计上可维护性与性能之间的权衡。在采用声明式提升可维护性的同时,性能就会有一定的损失,而架构设计者要做的就是:在保持可维护性的同时让性能损失最小化。
总结
命令式关注过程,声明式关注结果。
声明式代码可维护性更高,但相对于命令式会有性能损耗,所以架构设计时保证可维护性同时最小化性能损失,也就是最小化找出差异的性能损耗。