框架设计的基本概念
本篇文章主要了解框架设计中被经常涉及到的词汇如:声明式、命令式、运行时、编译时的基本概念。
命令式和声明式
命令式和声明式的区别在于,前者关注过程,后者关注结果。
命令式框架代表:jQuery。
例:
需求:
- 获取id为app的div标签
- 将他的文本内容设置为hello world
- 为其绑定点击事件
- 当点击时弹出提示:ok
$('#app')//获取dom
.text('hello world') //填充文字
.on('click',()=>{alert('ok')}) //绑定点击事件
代码本身描述做事的过程,如上例子中从”获取DOM元素”–>”为其填充文字”–>”为其绑定click事件”。
声明式框架代表:Vue
<div @click="()=>{ alert('ok') }">hello world</div>
Vue的实现方式像是通过这种语法模板,来告诉(委托)Vue,需要一个div
文本内容hello world需要绑定一个点击事件,完成上述操作。
我们不需要关注具体是如何实现的,Vue封装了实现的过程。
性能与可维护性
命令式和声明式各有优缺点,框架设计方面,差异体现在性能与可维护性之间。
性能
div.textcontent = 'hello vue3' //直接修改
<div>{{message}}</div> //寻找
原因:为了提升性能,Vue框架需要去寻找数据发生变化的地方再修改,把直接修改文本内容的性能消耗定义为A,把寻找差异的性能消耗定义为B。
- 命令式代码更新性能消耗 = A
- 声明式代码更新性能消耗 = B + A
结论:声明式代码的性能不优于命令式代码的性能。
我们还可以认为:框架本身直接封装了命令式代码才实现了面向用户的声明式,所以声明式性能只能无限接近命令式无法超过。
可维护性
声明式相对于命令式的优点在于可维护性强,所谓的可维护性指:代码可读性,对代码的增删改操作。我们只需要关注运行结果即可。
而框架的设计者要做的就是:在保持可维护性的同时让性能损失最小化
而Vue为了实现这一点便使用了虚拟DOM
运行时和编译时
纯运行时
纯运行时框架:运行时就是指代码实际执行时的阶段。
框架提供一个render函数,通过为框架提供特定树状结构的数据对象,通过render函数渲染成DOM元素。
const vnode = { type: 'div',
props: {
class: 'test'
},
children: 'hello render'
}
function render(vnode) {
const ele = document.createElement(vnode.type)
ele.className = vnode.props.class
ele.innerText = vnode.children
document.body.appendChild(ele)
}
render(vnode)
运行时+编译时
当运行时不能够满足用户需求,感觉书写这种特定的数据结构太麻烦,不够直观。可不可以用其他语法、方式来描述原来特定的数据结构,如:将HTML标签的方式编译为属性结构的数据对象,再进行render渲染。
而这个过程就是运行时+编译时,
为了满足用户的需求,就需要一个程序来将HTML标签编译成树状结构的数据对象,为此创建了一个compile
函数。
<div>
<span>hello world</span>
</div>`
通过compile
函数编译成特定数据对象
const obj = {
tag: 'div',
children: [
{
tag: 'span',
children: 'hello world'
}
]
}
再调用render
进行渲染。
const obj = compile(html)
render(obj, document.body)
这样框架就变成了一个运行时+编译时的框架。既支持运行时,用户直接提供特定数据对象来调用render渲染,也支持编译时执行compile
将html
标签编译成特定数据结构,再交由render函数进行渲染。
纯编译时
还有第三种情况就是纯编译时,编译器可以把HTML标签编译成数据对象,那么直接编译成命令行呢?
我们只需要一个compile
函数就可以了,这样就变成了纯编译时框架,因为我们不支持任何运行时内容,用户需要通过编译器编译后才能运行。
这三种方向上业内都有探索,其中Svelte就是纯编译时的框架,但是它的真实性能可能达不到理论高度。
Vue.js3仍然保持了运行时+编译时的架构,在保持灵活性的基础上能够尽可能地去优化。
原文链接:https://juejin.cn/post/7350602398619320370 作者:不想当废物的废物