文章基于对 Vue.js 核心团队成员的新书学习,外加个人理解,并未完全照搬书中代码和文字。推荐购买正版《Vue.js 设计与实现》进行深度学习。
命令式和声明式
命令式编程关注过程,典型的命令式编程库 jQuery:
// 获取 id 为 app 的 div 标签
$('#app')
// 设置文本类容为 hello world
.text('hello world')
// 点击时,内容修改为 hello jquery
.on('click', function () {
this.innerText = 'hello jquery'
})
命令式编程更符合普通思维方式,直接操作 DOM,性能也更好。
声明式编程关注结果,如 Vue:
{{ content }}
声明式编程符合 UI = f(x)
的函数思想,数据驱动视图,UI 修改过程交给框架,开发者只需要关注变量,减少维护时的心智负担。
总结:声明式编程的可维护性更好,但性能低于命令式,Vue 要做的就是保持可维护性的同时尽量减少性能损失。
虚拟 DOM 的性能
Vue 在初次渲染视图时,会生成一个 VNode,更新时又会生一个新的 VNode,将新旧两个 VNode 进行对比,找到最小修改差异,让进行修改,所以:
声明式代码的更新性能消耗 = 找出差异的性能消耗 + 修改 DOM 的性能消耗
理论上,直接原生 JavaScript 操作 DOM 性能更好,但这对开发者能力有较高的要求。在使用 jQuery 的时期,往往存在很多 innerHTML
暴力操作。
初次渲染时的性能对比
虚拟 DOM 耗时 = 创建 JavaScript 对象(VNode) + 全量 DOM 渲染
innerHTML 耗时 = 拼接 JavaScript 字符串 + 全量 DOM 渲染
更新时的性能对比
虚拟 DOM 耗时 = 创建新 JavaScript 对象(VNode) + Diff + 部分 DOM 渲染
innerHTML 耗时 = 拼接 JavaScript 字符串 + 全量 DOM 渲染
小结
操作虚拟 DOM 和操作原生 DOM 谁的性能更好,不能简单下结论。因为这跟如何操作 DOM,何时操作 DOM,修改量多少都有关。
虚拟 DOM 是保证运行性能、代码可维护性、降低心智负担的综合选择。
运行时与编译时
纯运行时
手写 DOM 对象,运行时直接遍历对象进行渲染,但书写麻烦。
var vnode = {
tag: 'div',
children: [
{
tag: 'span',
children: 'hello '
},
{
tag: 'span',
children: 'vue'
}
]
}
function render(vnode, parent) {
const el = document.createElement(vnode.tag)
const children = vnode.children
if (typeof children === 'string') {
el.innerHTML = vnode.children
}
if (Array.isArray(children) && children.length !== 0) {
children.forEach(child => {
render(child, el)
})
}
parent.appendChild(el)
}
render(vnode, document.body)
编译时 + 运行时
开发时写普通 HTML 模板:
hello
vue
构建时通过 compiler 进行编译:
const htmlString = '...'
const content = compile(htmlString)
运行时渲染:
render(content, document.body)
纯编译时
我们可以将模板编译成渲染函数或者 VNode,那同样也可以直接编译成原生 DOM 操作:
const htmlString = '...'
const content = compile(htmlString)
// 编译生成
const div = document.createElement('div')
const hello = document.createElement('span')
hello.innerHTML = 'hello '
div.appendChild(hello)
// ...
小结
纯运行时
以及编译时 + 运行时
的方式都可以通过不同的渲染器实现跨平台渲染,灵活性高。
但是纯运行时
书写麻烦,如果想做静态优化需要手动标记,而编译时 + 运行时
可以交给 compiler 去做。
纯编译时
理论上能获得最好的性能,但灵活性相对较弱。
综上
Vue 是一个编译时 + 运行时
的声明式
UI 框架,利用虚拟 DOM
进行更新渲染。保证其拥有良好的可维护性和灵活性,同时加上静态优化,尽可能接近原生的性能。