一、命令与声明,性能与维护
命令式:关注过程
- 获取div
- 设置文本内容
- 添加绑定事件
//jQuery
$('#app').text('hello world').on('click',()=>{alert('ok')})
声明式:关注结果
//Vue
<div @click="()=>alert('ok')">hello world</div>
声明式代码性能不会优于命令式代码的性能。
原因:Vue内部实现也是命令式,总体性能损耗=查找差异的性能+修改的性能。
例如要修改文本内容,Vue需要先找出差异,再通过div.textConten去修改。
框架设计理念:在保持可维护性的同时让性能损失最小化。
如果能尽可能减少查找差异的性能消耗,声明式的性能消耗就会尽可能的接近命令式,这就是虚拟DOM存在的原因。
二、运行与编译
框架设计层面可以分为:运行时,编译时,运行+编译
1.运行时
维护一个树形结构的js对象+可以把js对象转换成DOM节点的Render函数
function Render(obj, root) {
const el = document.createElement(obj.tag)
if (typeof obj.children === 'string') {
const text = document.createTextNode(obj.children)
el.appendChild(text)
} else if (obj.children) {
// array,递归调用 Render,使用 el 作为 root 参数
obj.children.forEach((child) => Render(child, el))
}
// 将元素添加到 root
root.appendChild(el)
}
const obj = {
tag: 'div',
children: [
{ tag: 'span', children: 'hello world' }
]
}
// 渲染到 body 下
Render(obj, document.body)
优点:不需要额外学习
缺点:用户需要维护obj这个树形数据结构,不够直观
2.编译时
直接将模板转换成命令式代码
<div>
<span>hello world</span>
</div>
const div = document.createElement("div");
const span = document.createElement("span");
span.innerText = "hello world";
div.append(span);
document.body.appendChild(div);
优点:理论上性能更好,直接命令式操作
缺点:不够灵活,无法进行分析优化
3.运行+编译
先把模板编译成虚拟DOM,再通过Render函数渲染成真实DOM(Vue3的)
//1.模板
const html=`
<div>
<span>hello world</span>
</div>
`
// 2.转换成虚拟对象
const obj=Compiler(html)
// obj={
// tag: 'div',
// children: [
// { tag: 'span', children: 'hello world' }
// ]
// }
//3.渲染到页面
Render(obj, document.body)
优点:可以在编译时分析哪些是长期不会变的部分,提供给Render函数,Render函数进一步会优化渲染过程,更加灵活
缺点:额外的性能开销
三、总结
本章中作者简单介绍了框架设计时的一些概念,命令式和声明式,进行了性能和可维护性层面的对比,创建页面,更新页面时需要考虑的性能影响,具体的更新策略要结合心智负担,可维护性和性能等层面综合考虑。