要讨论vue3的运行时和编译时框架设计,我们可以先来看看 什么叫命令式什么叫声明式?
首先我们先确定 Vue3是运行时+编译时的框架,其次我们再来看看为什么是?单纯的运行时或者编译时又有什么优缺点呢?
命令式框架最突出的就是关注编码过程,例如Jquery就是一个命令式框架哟。
- 获取id为content的div
- 设置文本内容为 hello vue
- 绑定点击事件
- 点击弹出 nice to meet you!
// 将其翻译为代码
$('#content').text('hello vue').on('click',()=>{alert('nick to meet you')})
// 原生写法
const div = doucument.querySelector('#content')
div.innerText = 'hello vue'
div.addEventListener('click',()=>{alert('nice to meet you')})
所以,命令式就是看中过程,有种隐隐的过程与代码的逻辑一一对应的感觉。
声明式更关注结果,内部过程则是予以封装了。
例如上面的代码可以用声明式的方式:
<div @click="() => alert('nick to meet you')">hello vue</div>
看起来很简洁吧,这是Vue封装后的。但Vue的内部实现一定是命令式的,只是暴露给开发者的是声明式的。
结论:声明式性能<=命令式性能
1.命令式代码更新性能消耗 = 修改消耗
2.声明式代码更新性能消耗 = 找出差异的消耗+ 修改差异的消耗
于是,Vue要做的就是,最小化找出差异的消耗,这里vue使用了虚拟DOM
虚拟DOM理论上不比原生JS性能高,但这是理论上,因为大多数情况下,写出绝对优化了命令式代码是消耗精力的。
然后,我们需要明确一点:JS对象操作的效率远高于DOM操作
那么,在创建页面时
虚拟DOM需要 创建虚拟JS对象(VNode)+新建DOM元素的Dom操作
命令式需要:渲染HTML字符串(js)+ 新建DOM元素的Dom操作
到目前为止,虚拟DOM可能性能上是小于等于命令式的
但轮到修改页面时:命令式需要进行全量的更新:重新获取HTML字符串 + 销毁DOM + 创建所有新DOM
虚拟DOM:创建js对象 + 找出差异(js层面) + 更新差异DOM
两者的性能差异随着页面变大也会越来越大。
我们先来看看
纯运行时模型:一个Render函数 + 符合树形结构的数据对象
// 数据对象
const obj = {
tag:'div',
children:[
{tag:'span',children:'hello vue'}
]
}
// render 函数
function Render(obj, root) {
const el = document.createElement(obj.tag)
if (typeof obj.children === 'string') {
const text = doucument.createTextNode(boj.children)
el.appendChild(text)
} else if (obj.children) {
//递归render,使用el作为root
obj.children.forEach(child => Render(child, el))
}
root.appendChild(el)
}
// 用户直接调用
Render(obj,doucument.body)
运行时 + 编译时模型:一个Render函数 + 一个Compiler函数 + html
const html = `hello vue`
const obj = Compiler(html)
Render(obj,doucument.body)
编译时模型: 一个Compiler函数 + html
const html = `hello vue`
const div = document.createElement('div')
const span = document.createElement('span')
span.innerText = 'hello vue'
div.appendChild(span)
document.body.appendChild(div)
这样就将其直接编译成了命令式代码
Vue3选择了运行时 + 编译时,并且其核心也是Diff算法。同时,Vue在保留运行时的情况下,性能也在逼近纯编译时。