权衡的艺术
...大约 3 分钟
命令式和声明式(视图层框架)
命令式
有如下特点:
- 自然语言描述能够与代码产生一一对应的关系,更加关注过程
- 早期流行的
jquery
就是典型的命令式框架,如下:
$('#app')
.text('hello world')
.on('click',() => {alert('ok')})
声明式
- 不关注过程,更加关注结果
- 当下流行的 vue 框架就是声明式的:
<div @click="() => alert('ok')">
hello word
</div>
性能与可维护性的权衡
声明式代码的性能差于命令式代码的性能
原因如下:
- 声明式代码比命令式代码多出找出差异的性能消耗
- 声明式代码本身就是封装了命令式代码才实现了面向用户的声明式
相关信息
命令式代码可以做到极致的优化,因为我们明确知道哪些发生了变更,只做必要的修改就行了
既然在性能层面命令式代码是更好的选择,那么为什么 Vue.js 要选择声明式的设计方案呢?
- 如果采用命令式代码开发,我们需要维护实现目标的整个过程,比较繁琐,而且可维护性较低
- 而声明式代码展示的就是我们要的结果,看上去更加直观
相关信息
在采用声明式提升可维护性的同时,性能就会有一定的损失,而框架设计者要做的就是:在保持可维护性的同时让性能损失最小化
虚拟 DOM 的性能到底如何
虚拟 DOM 存在的意义
最小化找出差异的性能消耗
相关信息
声明式代码的更新性能消耗 = 找出差异的性能消耗 + 直接修改的性能消耗
比较 innerHtml 和虚拟 DOM 的性能
innerHtml | 虚拟DOM | |
---|---|---|
创建页面的性能 | HTML 字符串拼接的计算量 + innerHtml 的 DOM 计算量 | 创建 JS 对象(VNode)的计算量 + 创建真实 DOM 的计算量 |
更新页面的性能 | 重新构建 HTML 字符串+销毁所有旧 DOM + 新建所有新DOM | 创建新的 JS 对象(VNode)+ 必要的DOM 更新 |
性能因素 | 与数据变化量相关 | 与模版大小相关 |
相关信息
纯 JS 层面的操作要比 DOM 操作快得多,它们不在一个数量级上
innerHtml | 虚拟DOM | 原生 JS | |
---|---|---|---|
心智负担 | 中等 | 小 | 大 |
可维护性 | 差 | 强 | 差 |
性能 | 差 | 中上 | 高 |
运行时和编译时
设计一个框架的时候,我们有三种选择:
- 纯运行时
- 纯编译时
- 运行时 + 编译时
首先我们来看三段代码:
输入
const obj = {
tag: 'div',
children:[
{
tag: 'span', children: 'hello world'
}
]
}
编译函数
function Compiler(html) {
return 上面的输入
}
渲染函数
function Render(obj,root) {
const el = document.creatElment(obj.tag)
if(typeof obj.children === 'string') {
const text = document.createTextNode(obj.children)
el.appendChild(text)
} else if (obj.children) {
obj.children.forEach(child => Render(child,el))
}
root.appendChild(el)
}
纯运行时
特点
没有编译过程
用户的代码不用编译直接可以运行
比如用户直接手写树型结构的数据对象,然后作为渲染函数的的入参
缺点
没有编译的过程,因此我们没办法分析用户提供的内容
用户心智负担较大
纯编译时
特点
不支持任何运行时的内容,用户的代码通过编译器编译后才能运行,例如 Svelte 框架
将html编译和渲染都放到编译器中去做,用户心智负担小
缺点
灵活性较差
运行时 + 编译时
将用户的代码进行编译处理成能够直接运行的代码
比如 vue
Powered by Waline v3.3.0