要知道 vue 为什么使用 运行时+编译时
,需了解 vue 的dom渲染
是如何进行的。
dom渲染 分两种情况:
- 初次渲染,通常被称为挂载;
- 更新渲染,通常被称为打补丁。
什么是初次渲染
在一个不含任何子节点的容器中挂载节点,就是初次渲染
,例如:
初始 div
的 innerHTML
为空时,
<div id="app"></div>
在该div
中渲染如下节点:
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
什么是更新渲染
在上面的案例中,如果渲染的内容发生了变化:
<ul>
<li>2</li>
<li>1</li>
<li>3</li>
</ul>
此时,你想到如何渲染呢?
有两种方式:
- 删除原有的所有
li
节点,重新渲染新的节点 - 删除原位置的
li : 2
,在新位置插入li : 2
我们来分析一下这两种方式区别:
- 首先对于第一种方式而言:它的好处在于不需要进行任何的比对,需要执行 6 次(删除 3 次,重新渲染 3 次)
dom
操作 - 对于第二种方式而言:主要是逻辑上的
js
计算,加上少量的dom
操作。他需要分成两步来做:- 对比 旧节点 和 新节点 之间的差异
- 根据差异,删除一个 旧节点,增加一个 新节点
那么这两种方式到底哪种更好呢?下面使用一个小测试看一下:
const length = 10000
// 增加一万个dom节点,耗时 3.992919921875 ms
console.time('element')
for (let i = 0; i < length; i++) {
const newEle = document.createElement('div')
document.body.appendChild(newEle)
}
console.timeEnd('element')
// 增加一万个 js 对象,耗时 0.402099609375 ms
console.time('js')
const divList = []
for (let i = 0; i < length; i++) {
const newEle = {
type: 'div'
}
divList.push(newEle)
}
console.timeEnd('js')
从结果可以看出,dom
的操作要比 js
的操作耗时多得多,即:dom
操作比 js
更加耗费性能。因此,方式一性能更差,方式二更好一些。
得出这样的结论之后,我们回归主题:为什么 vue 要设计成一个 运行时+编译时的框架呢?
- 针对于 纯运行时 而言:我们每次需要提供一个复杂的
JS
对象。 - 针对于 纯编译时 而言:因为缺少运行时,所以它只能把分析差异的操作,放到 编译时 进行,同样因为省略了运行时,速度可能会更快,但是这种方式这将损失灵活性。比如 svelte ,它就是一个纯编译时的框架,但是它的实际运行速度可能达不到理论上的速度。
因此vue
使用运行时 + 编译时相结合,使其可以在保持灵活性的基础上,尽量的进行性能的优化,从而达到一种平衡。