1
2
3
4 > if (options.optimize !== false) {
> optimize(ast, options)
> }
>
optimize
主要功能就是标记静态节点,为后面 patch 过程中对比新旧 VNode 树形结构做优化。被标记为 static 的节点在后面的 diff 算法中会被直接忽略,不做详细的比较。
optimize的目标:遍历生成的模板AST树并检测纯静态的子树,即永远不需要改变的dom。一旦我们检测到这些子树,我们就可以:
- 把它们提升成常数,这样我们就不再需要在每次重新渲染时为它们创建新节点;
- 在修补过程中完全跳过它们
函数如下:
1 | export function optimize (root: ?ASTElement, options: CompilerOptions) { |
markStatic - 标记所有非静态节点
1 | function markStatic (node: ASTNode) { |
isStatic函数 - 初步判断是否是静态节点(元素节点需特殊处理,详见👆)
1 | function isStatic (node: ASTNode): boolean { |
markStaticRoots - 标记静态根
ASTNode 的 type 字段用于标识节点的类型,可查看上一篇的 AST 节点定义:type 为 1 表示元素,type 为 2 表示插值表达式,type 为 3 表示普通文本。可以看到,在标记 ASTElement 时会依次检查所有子元素节点的静态标记,从而得出该元素是否为 static。上面 markStatic 函数使用的是树形数据结构的深度优先遍历算法,使用递归实现。
1 | function markStaticRoots (node: ASTNode, isInFor: boolean) { |
总结
optimizer旨在为语法树的节点标上static和staticRoot属性。
遍历第一轮,标记static属性:
- 判断node是否为static(有诸多条件)
- 标记node的children是否为static,若存在non static子节点,父节点更改为static = false
遍历第二轮,标记staticRoot
- 标记static或节点为staticRoot,这个节点type === 1(一般是含有tag属性的节点)
- 具有v-once指令的节点同样被标记staticRoot
- 为了避免过度优化,只有static text为子节点的节点不被标记为staticRoot
- 标记节点children的staticRoot