template 的 AST 与 vdom 的区别
简单说明 vue 在编译时生成的 AST 与运行时的 vdom 区别是什么。
vue 的渲染过程分为编译和运行两块,这也是为什么 vue.js 会提供了两个版本,一个是 runtime + compiler,一个只有 runtime。
compiler 做的就是将模板 template 编译成 render 函数。
整个渲染过程可以简单描述为:vue 源文件(template 模板)-> AST -> render 函数 -> vdom -> patch -> dom
AST(抽象语法树)
按照百度的解释,抽象语法树(Abstract Syntax Tree,AST),或简称语法树(Syntax tree),是源代码语法结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的一种结构。
用通俗的语言来说就是用 JS 对象描述特定语言的语法解构。
在 vue 的渲染过程中生成的 AST,其实就是用来描述 vue template 这种 dsl 的一个 JS 对象。
可以简单看一下,这是一个简单的 template 生成的抽象语法树,可以通过这个网站自行运行看一下:vue-template-compiler-playground
template 源码
<div>
<p>{{value}}</p>
<input v-model="inputValue" />
</div>
生成的 AST
{
"type": 1,
"tag": "div",
...
"children": [
{
"type": 1,
"tag": "p",
...
"children": [
...
],
...
},
...
{
"type": 1,
"tag": "input",
...
"directives": [
{
"name": "model",
"rawName": "v-model",
"value": "inputValue",
"arg": null,
"isDynamicArg": false
}
],
...
}
],
...
}
vdom(虚拟文档对象模型)
虚拟文档对象模型(virtual DOM),是用来描述 DOM 的 JS 对象。
简单看一下 vue vnode 的定义
export default class VNode {
tag: string | void;
data: VNodeData | void;
children: ?Array<VNode>;
text: string | void;
...
constructor (
tag?: string,
data?: VNodeData,
children?: ?Array<VNode>,
text?: string,
...
) {
this.tag = tag
this.data = data
this.children = children
this.text = text
...
}
...
}
他的核心是几个关键属性,标签名、数据、子节点、键值等,其它的都是用来支持 vue 的一些特性的。
vnode 的作用可以查看这片文章:vue.js 技术揭秘 - Virtual DOM。
结论
初看 template 生成的 AST 会跟 vdom 很像,其实通过描述就可以知道,两个其实都是用 JS 对象去描述特定的“语法”。template 是一种标记语法,而 vdom 描述的 DOM 也是由 html 这种标记语言抽象而来,两者描述的“语法”有相似性,故两者在很多方面有相似的点,例如都有 tag、attr 等。
但想想 vue dsl 的语言特性马上就能看出 ast 和 vdom 的区别,例如 vue dsl 中特有的指令,在编译后生成的就是 directives,这在 dom 上是没有的,所以 vdom 上也是不会有的。最终都为渲染和事件处理服务。
简单来说 template 编译出的 AST 就是为了描述模板表达的意思,后续的渲染方法才能根据 AST 表达的意思来用另外一门语言表达(HTML 等)。
本文部分内容参考vue.js 技术揭秘。