Appearance
运行时 + 编译时
前面两小节我们已经分别了解了 运行时 和 编译时 ,同时我们也知道了:vue是一个 运行时+编译时 的框架!
vue
通过comliler
解析html
模板,生成render
函数, 然后通过runtime
解析render
, 从而挂载真实dom
那么看到这里可能有些同学就会有疑惑了,既然 **compiler 可以直接解析 html 模板,**那么为什么还要生成 render 函数, 然后再去进行渲染呢? 为什么不直接利用 compiler 进行渲染呢?
即: 为什么 vue 要设计成一个 运行时 + 编译时的框架呢?
那么想要理清楚这个问题,我们就需要知道 dom 渲染是如何进行的
对于 dom
渲染而言, 可以被分为两个部分:
- 初次渲染,我们把它叫做 挂载
- 更新渲染,我们可以把它叫做 打补丁
初次渲染
当初始 div
的 inner HTML
为空时
html
<div id = "app"></div>
我们在该 div
中渲染如下节点:
html
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
这样的一次渲染,就是 初次渲染。在这样的一次渲染中,我们会生成一个ul
标签,同时生成三个li
标签,并且把他们挂载到div
中。
更新渲染
那么此时如果 ul
标签的内容发成了变化:
html
<ul>
<li>3</li>
<li>1</li>
<li>2</li>
</ul>
li - 3
上升到了第一位,那么此时可以想一下:我们期望浏览器如何来更新这次渲染呢?
浏览器更新这次渲染无非有两种方式:
- 删除原有的所有节点,重新渲染新的节点
- 删除原位置的
li - 3
,在新位置插入li - 3
那么这两种方式哪一种更好呢?那么我们来分析一下:
- 首先对于第一种方式而言:它的好处在于不需要进行任何的比对,需要执行6次(删除3次,重新渲染3 次)
dom
处理即可。 - 对于第二种方式而言,在逻辑上相对比较复杂。他需要分成两步来做:
- 对比 旧节点 和 新节点 之间的差异
- 根据差异,删除一个 旧节点,增加一个 新节点
根据以上分析,我们可以知道:
- 第一种方式:会涉及更多的
dom
操作 - 第二种方式:会涉及到
js
计算 + 少量的dom
操作
那么这两种方式哪一种更快呢?我们来试验一下:
js
// time.js
// 相同数量的 dom 操作 和 js 计算操作 哪一个更快
const length = 10000
// 增加一万个 dom 节点,查看耗时
console.time('element')
for (let i = 0; i < length; i++) {
const div = document.createElement('div')
document.body.appendChild(div)
}
console.timeEnd('element')
// 增加一万个 js 对象, 查看耗时
console.time('js')
const divList = []
for (let i = 0; i < length; i++) {
const ele = {
type: 'div'
}
divList.push(ele)
}
console.timeEnd('js')
从结果可以看出,dom
的操作要比js
的操作耗时多得多(demo中为10倍的差距),即:dom 操作比 js 更加耗费性能。
那么根据这样一个结论,回到刚刚我们所说的场景中:
- 首先对于第一种方式而言:它的好处在于不需要进行任何的比对,需要执行6次(删除3次,重新渲染3 次)
dom
处理即可。- 对于第二种方式而言,在逻辑上相对比较复杂。他需要分成两步来做:
- 对比 旧节点 和 新节点 之间的差异
- 根据差异,删除一个 旧节点,增加一个 新节点
根据结论可知: 方式一会比方式二更加消耗性能(即:性能更差)
得出这样的结论之后,我们回过头再去看最初的问题:为什么vue
要设计一个运行时+编译时的框架呢?
答: