Vue源码之compile之optimize

329 阅读2分钟

optimize

当我们的模板 template 经过 parse 过程后,会输出⽣成 AST 树,那么接下来我们需要对这颗树做优化,为什么要有优化过程,因为我们知道 Vue 是数据驱动,是响应式的,但是我们的模板并不是所有数据都是响应式的,也有很多数据是⾸次渲染后就永远不会变化的,那么这部分数据⽣成的 DOM 也不会变化,我们可以在 patch 的过程跳过对他们的⽐对。

markStatic

⾸先执⾏ node.static = isStatic(node),

isStatic 是对⼀个 AST 元素节点是否是静态的判断,

  • 如果是表达式,就是⾮静态;
  • 如果是纯⽂本,就是静态;
  • 如果添加了指令 v-pre,那么 node.pre 为 true,表明所有节点都不用解析了
  • 当节点有绑定 Vue属性的时候,比如指令,事件等,node.hasBindings 会为 true,⾮静态
  • 当 节点有 v-if 或者 v-for 的时候,node.if 或者 node.for 为true,⾮静态
  • 因为这两者是要动态编译的,不属于静态范畴所以只要是 slot 或者 component 都是⾮静态
  • ⾮内置组件,是平台保留的标签;
  • 父辈以上所有节点不能是 template 或者 带有 v-for;
  • 节点的所有属性的 key 都满⾜静态 key;

判断完后接着如果这个节点是⼀个普通元素也就是type=1,其次满足不是组件 标签名不为slot 并且存在inline-tempalte 才往下执行 否则直接return 因为组件需要更新不能标记为静态,否则遍历它的所有 children ,递归执⾏ markStatic ,如果某子节点不是静态节点,那么父节点就不能是静态节点。

因为所有的elseif 和 else 节点都不在 children 中, 如果节点的 ifConditions 不为空,则遍历ifConditions 拿到所有条件中的 block ,也就是它们对应的 AST 节点,递归执⾏markStatic 。在这些递归过程中,⼀旦⼦节点有不是 static 的情况,则它的⽗节点的 static均变成 false。

markStaticRoots

对于有资格成为 staticRoot 的节点,首先它是一个元素节点也就是Type=1,其次除了本⾝是⼀个静态节点外,必须满⾜拥有children ,并且 children 不能只是⼀个⽂本节点,官方解释是成本大于收益。接下来和标记静态节点的逻辑⼀样,遍历 children 以及 ifConditions ,递归执⾏markStaticRoots 。

总结

optimize 的过程,就是深度遍历AST 树,去检测它的每⼀颗⼦树是不是静态节点,如果是静态节点则它们⽣成 DOM 永远不需要改变,这对运⾏时对模板的更新起到极⼤的优化作⽤。我们通过 optimize 我们把整个 AST 树中的每⼀个 AST 元素节点标记了 static 和staticRoot ,它会影响我们接下来执⾏代码⽣成的过程。