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 技术揭秘