最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue.js 源码(11)—— 优化器

    正文概述 掘金(Camol)   2021-06-15   581

    这是我参与更文挑战的第11天,活动详情查看: 更文挑战。

    前言

    前面我们学习了模板编译中的解析器,这次我们将学习优化器。

    优化器

    什么是静态子树?

    静态子树指的是那些在 AST 中永远都不会发生变化的节点。例如,一个纯文本节点就是静态子树,而带变量的文本节点就不是静态子树,因为它会随着变量的变化而变化。

    好处

    标记静态子树有两点好处:

    • 每次重新渲染时,不需要为静态子树创建新节点
    • 虚拟DOM 中打补丁(patching)的过程可以跳过

    为什么重新渲染时,不需要为静态子树创建新节点?

    前面我们有讲过克隆节点。在生成VNode的过程中,如果发现一个节点被标记为静态子树,那么除了首次渲染会生成节点之外,在重新渲染时并不会生成新的子节点树,而是克隆已存在的静态子树。

    为什么在 patch 阶段可以跳过?

    如果两个节点都是静态子树,就不需要进行对比与更新 DOM 的操作,直接跳过。因为静态子树是不可变的,不需要对比就知道它不可能发生变化。此外,直接跳过后续的各种对比可以节省 JavaScript 的运算成本。

    内部实现

    优化器的内部实现主要分为两个步骤:

    • 在AST中找出所有静态节点并打上标记
    • 在AST中找出所有静态根节点并打上标记

    类似下面的节点就是静态节点:

    <p>我是静态节点<p>
    

    对应到 AST 中,就是节点的statictrue,如果是静态根节点,staticRoot 也为true

    找出所有静态节点并标记

    递归 AST,使用 isStatic 函数来判断节点是否是静态节点,然后如果节点的类型等于1,说明节点是元素节点,那么循环该节点的子节点,调用 markStatic 函数用同样的处理逻辑来处理子节点:

    function markStatic(node){
        node.static = isStatic(node);
        if (node.type === 1) {
            for (let i = 0, l = node.children.length; i<l;i++){
                const child = node.children[i];
                markStatic(child);
            }
        }
    }
    

    什么样的节点是静态节点?

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

    type说明
    1元素节点2带变量的动态文本节点3不带变量的纯文本节点

    显而易见,没有变量的文本节点肯定是静态节点,然后没有使用v-ifv-elsev-for,或没有使用v-bind也是静态节点。

    自定义组件或者内置组件也不会是静态节点。

    由于递归是从上向下依次标记的,如果父节点被标记为静态节点之后,子节点却被标记为动态节点,这时就会发生矛盾。因为静态子树中不应该只有它自己是静态节点,静态子树的所有子节点应该都是静态节点。因此,我们需要在子节点被打上标记之后重新校对当前节点的标记是否准确。

    function markStatic(node){
        node.static = isStatic(node);
        if (node.type === 1) {
            for (let i = 0, l = node.children.length; i<l;i++){
                const child = node.children[i];
                markStatic(child);
                // 新增
                if(!child.static){
                    node.static = false
                }
            }
        }
    }
    

    我们需要判断它是否是静态节点,如果不是,那么它的父节点也不可能是静态节点。

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

    找出静态根节点的过程与找出静态节点的过程类似,都是使用递归的方式。如果一个节点被判定为静态根节点,那么将不会继续向它的子级继续寻找。

    graph 
        root((root)) --找到--> a((静态))
        root --没找到--> b((b))
        b --找到--> c((静态))
        
        a --> d((静态))
        a --> e((静态))
        
        c --> f((静态))
        c --> g((静态))
    

    有一种情况,即便它真的是静态根节点,也不会被标记为静态根节点,因为其优化成本大于收益。这种情况是一个元素节点只有一个文本节点。

    例如:

    <p>我是静态节点<p>
    

    p元素只有一个文本子节点,此时即便它是静态根节点,也不会被标记。

    function markStaticRoots(node){
        if (node.type === 1) {
            if (node.static && node.children.length && !(node.children.length === 1 && node.children[0].type === 3)){
                node.staticRoot = true;
                return;
            } else {
                node.staticRoot = false;
            }
            if (node.children) {
                for (let i = 0, l = node.children.length; i<l;i++){
                    markStaticRoots(node.children[i])
                }
            }
            
        }
    }
    

    总结

    本文,我们学习了优化器的作用和原理,后面我们将学习模板编译的第三部分——代码生成器


    起源地下载网 » Vue.js 源码(11)—— 优化器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元