Skip to content
On this page

运行时 + 编译时

前面两小节我们已经分别了解了 运行时编译时 ,同时我们也知道了:vue是一个 运行时+编译时 的框架!

vue 通过 comliler 解析 html 模板,生成 render 函数, 然后通过 runtime 解析 render, 从而挂载真实 dom

那么看到这里可能有些同学就会有疑惑了,既然 **compiler 可以直接解析 html 模板,**那么为什么还要生成 render 函数, 然后再去进行渲染呢? 为什么不直接利用 compiler 进行渲染呢?

即: 为什么 vue 要设计成一个 运行时 + 编译时的框架呢?

那么想要理清楚这个问题,我们就需要知道 dom 渲染是如何进行的

对于 dom 渲染而言, 可以被分为两个部分:

  1. 初次渲染,我们把它叫做 挂载
  2. 更新渲染,我们可以把它叫做 打补丁

初次渲染

当初始 divinner 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上升到了第一位,那么此时可以想一下:我们期望浏览器如何来更新这次渲染呢?

浏览器更新这次渲染无非有两种方式:

  1. 删除原有的所有节点,重新渲染新的节点
  2. 删除原位置的li - 3,在新位置插入li - 3

那么这两种方式哪一种更好呢?那么我们来分析一下:

  1. 首先对于第一种方式而言:它的好处在于不需要进行任何的比对,需要执行6次(删除3次,重新渲染3 次)dom处理即可。
  2. 对于第二种方式而言,在逻辑上相对比较复杂。他需要分成两步来做:
    1. 对比 旧节点新节点 之间的差异
    2. 根据差异,删除一个 旧节点,增加一个 新节点

根据以上分析,我们可以知道:

  1. 第一种方式:会涉及更多的dom操作
  2. 第二种方式:会涉及到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 更加耗费性能

那么根据这样一个结论,回到刚刚我们所说的场景中:

  1. 首先对于第一种方式而言:它的好处在于不需要进行任何的比对,需要执行6次(删除3次,重新渲染3 次)dom处理即可。
  2. 对于第二种方式而言,在逻辑上相对比较复杂。他需要分成两步来做:
    1. 对比 旧节点新节点 之间的差异
    2. 根据差异,删除一个 旧节点,增加一个 新节点

根据结论可知: 方式一会比方式二更加消耗性能(即:性能更差)

得出这样的结论之后,我们回过头再去看最初的问题:为什么vue要设计一个运行时+编译时的框架呢?

答:

  1. 针对于 纯运行时 而言:因为不存在编译器,所以我们只能提供一个复杂的 js对象。
  2. 针对于 纯编译时 而言:因为缺少运行时,所以它只能把分析差异的操作,放到 编译时进行,同样因为省略了运行时,所以速度可能会更快。但是这种方式将损失灵活性(具体可查看第六章虚拟 DOM,也有vue官方提供的示例)。比如 svelte,它就是一个纯编译时的框架,但是它的实际运行速度可能达不到理论上的速度。
  3. 运行时 + 编译时:比如 vuereact 都是通过这种方式来进行构建的,使其可以在保持灵活性的基础上,尽量的进行性能优化,从而达到一种平衡。

Released under the MIT License.