图片授权基于CC0协议
上一篇写了Vue是如何生成虚拟DOM的,把 template 里面的代码转成字符串,利用状态机去匹配,然后生成AST树。这就相当于把页面的属性、事件都循环遍历到AST树里面了。
然后…迎来了优化。
在这一步Vue做了很关键的一步,就是标记静态节点。
optimize方法
-
标记非静态节点 markStatic(root)
此方法是用来标记 AST 树哪些节点是非静态的。
循环 AST 树,用 type 来做判断,通过 isStatic 再来标记非静态节点「上篇文章在生成 AST树的时候就标记好了 type 类型」
type = 2 表达式「要实时变化」
type = 3 纯文本
其他的就属于 type = 1 流程。
在递归过程中判断是否是静态,在深度遍历的过程中,如果AST中有 children 就会递归判断子节点来判断 isStatic,只要有子级是非静态的,这个时候父级就标记为非静态。
如果全部子节点为静态的时候,父级才标记静态。
<div>web</div>
比如:一个纯文本节点标记 static 为 true,那它的根节点 staticRoot 也会标记为 true。
-
标记静态根 markStaticRoots(root)
标记了静态根,响应数据更新的时候不会被重新渲染,以此来提升渲染速度。
递归「循环遍历」的目的为了标明根节点的 isStatic 是否为 true;
其实 staticRoot 才是真正判断是否需要更新的依据;
通过标记静态根的方式来优化重新渲染过程中对静态节点的处理逻辑。先标记静态节点,再标记静态根。
codegen 生成可执行代码
export function installRenderHelpers (target: any) {
target._o = markOnce
target._n = toNumber
target._s = toString
target._l = renderList
target._v = createTextVNode
target._e = createEmptyVNode
...
}
codegen 的目标是把 AST 树转换成代码字符串。
_c 就是执行 createElement 去创建 VNode,而 _l 对应 renderList 渲染列表;_v 对应 createTextVNode 创建文本 VNode;_e 对于 createEmptyVNode创建空的 VNode。
export function genElement (el: ASTElement, state: CodegenState): string {
if (el.staticRoot && !el.staticProcessed) {
return genStatic(el, state)
} else if (el.once && !el.onceProcessed) {
return genOnce(el, state)
} else if (el.for && !el.forProcessed) {
return genFor(el, state)
} else if (el.if && !el.ifProcessed) {
return genIf(el, state)
} else if (el.tag === \\\'template\\\' && !el.slotTarget) {
return genChildren(el, state) || \\\'void 0\\\'
} else if (el.tag === \\\'slot\\\') {
return genSlot(el, state)
} else {
// component or element
}
}
生成for函数、生成else函数、生成if函数、生成子节点。
整个 codegen 过程就是深度遍历AST树,然后根据不同的条件去生成不同的代码块。
这块内容我理解的不是很深入,需要后面再根据具体的流程来深入学习。
好像又留了一个坑…
参考资料:
[1]《Vue.js源码全方位深入解析》
[2] https://www.kancloud.cn/zmwtp/vue2/148822
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34482.html