优化器的是在AST中找出静态子树并打上标记。静态子树指的是那些在AST中永远不会发生变化的节点。纯文本节点就是静态子树,而带变量的文本节点就不是静态子树,它会随着变量的变化而变化。
标记静态子树有两个好处:
1.在每次重新渲染时,不需要为静态子树创建新节点(使用克隆节点)
2.在虚拟DOM中打补丁(patching)的过程可以跳过。直接跳过后续的各种对比就可以节省js的运算成本。
优化器内部实现主要分为两个步骤:
1.在AST中找出所有静态节点并打上标记
2.在AST中找出所有静态根节点并打上标记,静态根节点就是一个节点如果下面的所有子节点都是静态节点,并且它的父级是动态节点,那么它就是静态根节点。落实到AST中,静态根节点指的是staticRoot属性为true的节点。AST中多了static和staticRoot属性来标记节点是否是静态节点与是否是静态根节点。

找出所有静态节点并标记

从根节点开始,先判断根节点是不是静态根节点,再用相同的方式处理子节点,接着用同样的方式去处理子节点的子节点,直到所有节点都被处理之后程序结束,这个过程叫作递归。

当模板被解析器解析成AST时,会根据不同元素类型设置不同的type值。

type的值 说明

1 元素节点 可能是静态也可能不是
2 带变量的动态文本节点 不是静态节点
3 不带变量的纯文本节点 是静态节点
判断一个元素节点是否是静态节点:
如果一个元素使用了指令v-pre 说明这是一个静态节点。
如果元素节点没有使用指令v-pre,则满足以下条件才会被认为是一个静态节点
1.不能使用动态绑定语法,也就是标签上不能有以v-、@、:开头的属性
2.不能使用v-if、v-for或者v-else指令
3.不能是内置标签,也就是说标签名不能是slot或者component
4.不能是组件,即标签名必须是保留标签,例如div,而list不是保留标签
5.当前节点的父节点不能是带v-for指令的template标签
6.节点中不存在动态节点才会有的属性

找出所有的静态根节点并标记

找静态根节点和静态节点的过程类似,都是从根节点开始向下一层一层地用递归方式去找,如果一个节点被判为静态根节点,则不会继续向它地子级继续寻找。
一般情况下,找到的的第一个静态节点会被标记为静态根节点,但是有一种情况,即便真的是静态根节点,也不会被标记为静态根节点,因为其优化成本大于收益。
<p>我是静态节点</p>这个p元素只有一个文本子节点,即便它是静态根节点,也不会被标记