# 简介
在上一章节中,我们详细讲述了虚拟DOM
的相关知识,其中大部分都是虚拟DOM
拿到vnode
之后所做的事情。那么vnode
是怎样生成的呢?这就涉及到我们本章节要研究的内容模板编译
。
# 完整渲染流程
我们在平时使用Vue的开发过程中,可以在模板中使用变量填充,也可以在模板中直接使用JavaScript表达式或者使用自定义的指令等。
这些功能在标准的HTML语法中是不存在的,那为什么会在浏览器正确的展示出来呢,要探究这个问题,我们需要先了解下 Vue 完整渲染流程。
- 用户编写模板:用户通过Vue提供的模板语法声明式的描述界面
- 模板编译:Vue将用户编写的模板进行解析和处理
- render函数:模板编译完成后,输出的就是render函数
- vnode:执行render函数,生成vnode
- patch:通过diff算法等操作对vnode树进行处理
- 视图: 处理完毕后的vnode树生成真实的视图
在这个流程中,我们将前三个阶段称为模板编译阶段
,后三个阶段称为虚拟DOM阶段
。
所以我们可以得出一个结论,浏览器能够正确渲染出我们使用的模板语法的原因就是Vue在渲染过程中使用了模板编译
,而模板编译
就是将用户编写的模板通过一系列处理最终生成render函数
的过程。
# AST
我们都知道,我们在<template></template>
标签中写的模板对Vue来说就是一堆字符串,那么如何解析这一堆字符串并且从中提取出元素的标签、属性、变量插值等有效信息呢?这就需要借助一个叫做抽象语法树(AST)的东西。
抽象语法树(AbstractSyntaxTree,AST),简称语法树(Syntax tree),是源代码的抽象语法结构的树状表现形式。一个 AST 只包含与分析源文本有关的信息,而跳过任何其他在解析文本时使用的额外内容(例如什么分号,函数参数中的逗号之类的对程序没有意义的东西)
简单来说,如果虚拟DOM
是用js对象
表示真实DOM
,那么AST
就是用一种特殊的抽象树状结构
表示代码的抽象语法结构
。
我们可以借助语法树工具AST Explorer (opens new window)直观的感受。
上述示例表示了一个简单的HTML
片段被转换成了一个特殊的树状结构
。这个结构中的属性描述了HTML
片段的关键信息。
# 模板编译内部流程
将模板编译成render函数
可以分为两个步骤
- 将模板解析成
AST
- 使用
AST
生成render函数
有些同学就比较疑惑,为什么中间要使用AST
中转一下,直接将模板生成render函数
多好,还省去中转的损耗的性能。实际通过模板语法直接转换为render函数
的算法难度比较大,而AST
本身就是一种成熟的方案,所以在框架的权衡下使用了AST
方案。
在上一章节中,我们说过一种特殊的节点,静态节点。静态节点特性就是只渲染一次,所以为了性能优化,在生成AST
之后,生成render函数
之前,需要遍历AST
,给静态节点增加一个标记,以便后续虚拟DOM
处理时,不会重复渲染。
所以,在 Vue 中,模板编译成render函数
分为三部分
- 解析器:将模板解析成
AST
- 优化器:遍历
AST
标记静态节点 - 代码生成器:使用
AST
生成render函数
这三个阶段在源码中分别对应三个模块,下面给出三个模块的源代码在源码中的路径:
- 解析器——源码路径:
src/compiler/parser/index.js
- 优化器——源码路径:
src/compiler/optimizer.js
- 代码生成器——源码路径:
src/compiler/codegen/index.js
流程图如下: