最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue原理Compile之optimize標(biāo)記靜態(tài)節(jié)點(diǎn)源碼示例

 更新時間:2022年07月13日 11:17:05   作者:神仙朱  
這篇文章主要為大家介紹了vue原理Compile之optimize標(biāo)記靜態(tài)節(jié)點(diǎn)源碼示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

引言

optimize這一步的內(nèi)容好像不太多,但是非常重要,于是是一個更新性能優(yōu)化, 非常重要

先來看看 optimize 在什么位置,就在 parse 處理完之后,generate 之前

var ast = parse(template.trim(), options);
if (options.optimize !== false) {
    optimize(ast, options);
}
var code = generate(ast, options);

上面這段代碼在函數(shù) baseCompile 中,如果想了解的,看這里 Compile - 從新建實例到 compile結(jié)束的主要流程

而 optimize 的作用是什么呢?

Vue官方注釋

優(yōu)化器的目標(biāo)

遍歷生成的模板AST樹,檢測純靜態(tài)的子樹,即永遠(yuǎn)不需要更改的DOM。

一旦我們檢測到這些子樹,我們可以:

1、把它們變成常數(shù),這樣我們就不需要了在每次重新渲染時為它們創(chuàng)建新的節(jié)點(diǎn)

2、在修補(bǔ)過程中完全跳過它們。

那是怎么做的呢?

給靜態(tài)ast節(jié)點(diǎn)設(shè)置屬性 static,當(dāng)節(jié)點(diǎn)時靜態(tài)是

el.static = true

下面就來看下源碼

function optimize(root, options) {    
    if (!root) return
    // first pass: mark all non-static nodes.
    markStatic$1(root);    
    // second pass: mark static roots.
    markStaticRoots(root);
}

里面主要調(diào)用了兩個函數(shù),這兩個函數(shù)會分別分析

但是在此之前,我們先來看一個函數(shù),這個函數(shù)就是 判斷靜態(tài)節(jié)點(diǎn)的 主力函數(shù)

直接傳入 ast 節(jié)點(diǎn),各種組合判斷,然后給 ast 節(jié)點(diǎn)添加上 static 屬性

function isStatic(node) {    
    // 文字表達(dá)式
    if (node.type === 2) return false
    // 純文本
    if (node.type === 3) return true
    return (        
        // 設(shè)置了 v-pre 指令,表示不用解析
        node.pre ||
        (
            !node.hasBindings && // 沒有動態(tài)綁定
            ! node.if && !node.for && // 不存在v-if ,v-for 指令
            ! ['slot','component'].indexOf(node.tag)>-1 && // 需要編譯的標(biāo)簽
            isPlatformReservedTag(node.tag) && // 正常html 標(biāo)簽
            ! isDirectChildOfTemplateFor(node) &&
            Object.keys(node).every(isStaticKey)
        )
    )
}

如果要判斷為靜態(tài)節(jié)點(diǎn),就要經(jīng)過下面7個條件的審判(把上面的代碼列了出來)

1 是否存在 v-pre

如果添加了指令 v-pre,那么 node.pre 為 true,表明所有節(jié)點(diǎn)都不用解析了

2 不能存在 node.hasBindings

當(dāng)節(jié)點(diǎn)有綁定 Vue屬性的時候,比如指令,事件等,node.hasBindings 會為 true

3 不能存在 node.if 和 node.for

同樣,當(dāng) 節(jié)點(diǎn)有 v-if 或者 v-for 的時候,node.if 或者 node.for 為true

4 節(jié)點(diǎn)名稱不能是slot 或者 component

因為這兩者是要動態(tài)編譯的,不屬于靜態(tài)范疇

所以只要是 slot 或者 component 都不可能是靜態(tài)節(jié)點(diǎn)

5 isPlatformReservedTag(node.tag)

isPlatformReservedTag 是用于判斷該標(biāo)簽是否是正常的HTML 標(biāo)簽,有什么標(biāo)簽?zāi)兀?/p>

標(biāo)簽必須是正常HTML標(biāo)簽,如下

html,body,base,head,link,meta,style,title

address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section

div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul

a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby

s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video

embed,object,param,source,canvas,script,noscript,del,ins

caption,col,colgroup,table,thead,tbody,td,th,tr

button,datalist,section,form,input,label,legend,meter,optgroup,option

output,progress,select,textarea

details,dialog,menu,menuitem,summary

content,element,shadow,template,blockquote,iframe,tfoot

svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face

foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern

polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view

是不是挺多的,哈哈,尤大真厲害,估計收集了很多,我覺得應(yīng)該有用,就全放上來了

6 isDirectChildOfTemplateFor(node)

看下這個函數(shù)的源碼

function isDirectChildOfTemplateFor(node) {    
    while (node.parent) {
        node = node.parent;        
        if (node.tag !== 'template') {            
            return false
        }        
        if (node.for) {            
            return true
        }
    }    
    return false
}

表明了節(jié)點(diǎn)父輩以上所有節(jié)點(diǎn)不能是 template 或者 帶有 v-for

7 Object.keys(node).every(isStaticKey)

isStaticKey是一個函數(shù),用于判斷傳入的屬性是否在下面的范圍內(nèi)

type,tag,attrsList,attrsMap,plain,parent,children,attrs

比如這樣的 ast

<div style="" ></div>
{    
    attrsList: []
    attrsMap: {style: ""}
    children: []
    parent: undefined
    plain: false
    tag: "div"
    type: 1
}

上面的 ast 的所有屬性通過 isStaticKey 判斷之后,都在上面列出的屬性范圍中,都是靜態(tài)屬性,所以這就是一個靜態(tài)節(jié)點(diǎn)

而當(dāng)你存在之外的其他屬性的時候,這個節(jié)點(diǎn)就不是靜態(tài)ast

然后下面就來看 optimize 中出現(xiàn)的兩個函數(shù)把

markStatic$1 和 markStaticRoot

標(biāo)記靜態(tài)節(jié)點(diǎn)

怎么標(biāo)記一個節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)呢,就在 markStatic$1 中進(jìn)行處理

// 標(biāo)記節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)
function markStatic$1(node) {
    node.static = isStatic(node);    
    if (node.type !== 1) return
    // 不要將組件插槽內(nèi)容設(shè)置為靜態(tài)。
    // 這就避免了
    // 1、組件無法更改插槽節(jié)點(diǎn)
    // 2、靜態(tài)插槽內(nèi)容無法熱加載
    if (        
        // 正常 thml 標(biāo)簽 才往下處理,組件之類的就不可以
        !isPlatformReservedTag(node.tag) &&
        // 標(biāo)簽名是 slot 才往下處理
        node.tag !== 'slot' &&
        // 有 inline-tempalte 才往下處理
        node.attrsMap['inline-template'] == null
    ) {        
        return
    }    
    // 遍歷所有孩子,如果孩子 不是靜態(tài)節(jié)點(diǎn),那么父親也不是靜態(tài)節(jié)點(diǎn)
    var l = node.children.length    
    for (var i = 0;i < l; i++) {        
        var child = node.children[i];  
        // 遞歸設(shè)置子節(jié)點(diǎn),子節(jié)點(diǎn)再調(diào)用子節(jié)點(diǎn)
        markStatic$1(child);        
        if (!child.static) {
            node.static = false;
        }
    }    
    if (node.ifConditions) {    
        var c = node.ifConditions.length  
        for (var j = 1; j < c; j++) {    
            // block 是 節(jié)點(diǎn)的 ast
            var block = node.ifConditions[j].block;
            markStatic$1(block);  
            if (!block.static) {
                node.static = false;
            }
        }
    }
}

這個方法做了下面三種事情

1 isStatic 這個方法對 ast 節(jié)點(diǎn)本身進(jìn)行初步判斷

進(jìn)行初步靜態(tài)節(jié)點(diǎn)判斷

2 判斷靜態(tài)節(jié)點(diǎn)的額外的處理

給節(jié)點(diǎn)本身判斷完是否靜態(tài)節(jié)點(diǎn)之后,需要做額外的處理,就是需要檢查所有的子孫節(jié)點(diǎn)

于是便會逐層遞歸子節(jié)點(diǎn),如果某子節(jié)點(diǎn)不是靜態(tài)節(jié)點(diǎn),那么父節(jié)點(diǎn)就不能是靜態(tài)節(jié)點(diǎn),但是并不是所有節(jié)點(diǎn)都會進(jìn)行特殊處理,是有條件的

節(jié)點(diǎn)類型是 1

  • 類型 1 是 標(biāo)簽元素
  • 類型 2 是 文字表達(dá)式
  • 類型 3 是 純文本

3 是正常 html 標(biāo)簽,標(biāo)簽是 slot,存在 inline-template 屬性

1、必須是正常標(biāo)簽,也就是說自定義標(biāo)簽不需要再次處理

2、slot 會額外處理

3、有 inline-template 屬性也會額外處理

只有有一個滿足,就會進(jìn)行額外處理

疑點(diǎn)

你可以看到源碼中的最后一步

判斷 node.ifCondition,并且如果 ifCondition 中保存的節(jié)點(diǎn)不是靜態(tài)的話,那么這個 node 也不是靜態(tài)節(jié)點(diǎn)

這個判斷就很讓我匪夷所思了

明明如果存在 v-if 的話,該節(jié)點(diǎn)在 一開始的 isStatic 中,就會被設(shè)置 node.static 為 false 了

為什么還要在末尾 再判斷一遍呢?

這里我覺得好像有點(diǎn)多余?反正我沒有想通 尤大 的想法啊啊啊啊啊,為了確保正確?

經(jīng)過這一步,所有的節(jié)點(diǎn),都會被添加上 static 屬性,節(jié)點(diǎn)是否靜態(tài),一看便知

標(biāo)記靜態(tài)根節(jié)點(diǎn)

// 標(biāo)記根節(jié)點(diǎn)是否是靜態(tài)節(jié)點(diǎn)
function markStaticRoots(node) {    
    if (node.type === 1) return
    // 要使一個節(jié)點(diǎn)符合靜態(tài)根的條件,它應(yīng)該有這樣的子節(jié)點(diǎn)
    // 不僅僅是靜態(tài)文本。否則,吊裝費(fèi)用將會增加
    // 好處大于好處,最好總是保持新鮮。
    if (        
        // 靜態(tài)節(jié)點(diǎn)
        node.static &amp;&amp;        
        // 有孩子
        node.children.length &amp;&amp;        
        // 孩子有很多,或者第一個孩子不是純文本
        ! (node.children.length === 1 
            &amp;&amp; node.children[0].type === 3
          )
    ) {
        node.staticRoot = true;        
        return
    }
    else {
        node.staticRoot = false;
    }    
    if (node.children) {    
        var l = node.children.length    
        for (var i = 0; i &lt; l; i++) {
            markStaticRoots(
                node.children[i]
            );
        }
    }
}

這個方法只會不斷的尋找 靜態(tài)的根節(jié)點(diǎn),應(yīng)該說是區(qū)域根節(jié)點(diǎn)吧,反正一個節(jié)點(diǎn)下面有馬仔節(jié)點(diǎn),這個節(jié)點(diǎn)就算是根節(jié)點(diǎn)

遞歸他的所有子孫,看看誰是靜態(tài)根節(jié)點(diǎn),如果是靜態(tài)ast,就會被添加上 staticRoot 這個屬性

markStaticRoots 也是遞歸調(diào)用的,但是并不是會處理到所有節(jié)點(diǎn)

因為找到一個根節(jié)點(diǎn)是靜態(tài)根節(jié)點(diǎn)后,就不會遞歸處理他的子節(jié)點(diǎn)了

然后我們需要了解兩個問題

1、markStaticRoot 和 markStatic$1 的區(qū)別

2、判斷靜態(tài)根節(jié)點(diǎn)的依據(jù)是什么

markStaticRoots 和 markStatic$1 有什么區(qū)別?

找出靜態(tài)根節(jié)點(diǎn)才是性能優(yōu)化的最終作用者

markStatic$1 這個函數(shù)只是為 markStaticRoots 服務(wù)的,是為了先把每個節(jié)點(diǎn)都處理之后,更加方便快捷靜態(tài)根節(jié)點(diǎn),可以說是把功能分開,這樣處理的邏輯就更清晰了

先給所有的節(jié)點(diǎn)都劃分身份,之后處理靜態(tài)節(jié)點(diǎn)時,只用找 那部分的根節(jié)點(diǎn)(區(qū)域負(fù)責(zé)人就好了)

當(dāng)然,上面都是我個人的理解,那么我的依據(jù)是什么呢?

markStatic$1 添加的 static 屬性,我全局搜索,并沒有在處理DOM和 生成 render上使用過

而 markStaticRoots 添加的 staticRoot ,在生成 render 上使用了

而且再 根據(jù) markStaticRoots 寫的功能邏輯 并 使用了 static 屬性進(jìn)行判斷

所以我認(rèn)為 markStatic$1 是為 markStaticRoots 服務(wù)的一個函數(shù)

被判斷為靜態(tài)根節(jié)點(diǎn)的條件是什么?

1該節(jié)點(diǎn)的所有子孫節(jié)點(diǎn)都是靜態(tài)節(jié)點(diǎn)

而 node.static = true 則表明了其所有子孫都是靜態(tài)的,否則上一步就被設(shè)置為 false 了

2必須存在子節(jié)點(diǎn)

3子節(jié)點(diǎn)不能只有一個 純文本節(jié)點(diǎn)

這一點(diǎn)我不太明白,為什么只有一個純文本子節(jié)點(diǎn)時,這個點(diǎn)不能是靜態(tài)根節(jié)點(diǎn)?

注意:只有純文本子節(jié)點(diǎn)時,他是靜態(tài)節(jié)點(diǎn),但是不是靜態(tài)根節(jié)點(diǎn)。靜態(tài)根節(jié)點(diǎn)是optimize 優(yōu)化的條件,沒有靜態(tài)根節(jié)點(diǎn),說明這部分不會被優(yōu)化

而 Vue 官方說明是,如果子節(jié)點(diǎn)只有一個純文本節(jié)點(diǎn),如果優(yōu)化的話,帶來的成本就比好處多了,所以就不優(yōu)化

那么我就疑惑了

為什么子節(jié)點(diǎn)只有是靜態(tài)文本時,成本會大?

下面是我的個人探索的想法

首先,我們明確,優(yōu)化的好處是,減少DOM比對,加速更新

而帶來的成本是什么呢?

1、維護(hù)靜態(tài)模板存儲對象

2、多層函數(shù)調(diào)用

現(xiàn)在我們來簡單解釋下上面兩種成本

1 維護(hù)靜態(tài)模板存儲對象

一開始的時候,所有的靜態(tài)根節(jié)點(diǎn) 都會被解析生成 VNode,并且被存在一個緩存對象中,就在 Vue.proto._staticTree 中

比如下面這個靜態(tài)模板

解析后被存了進(jìn)去

隨著靜態(tài)根節(jié)點(diǎn)的增加,這個存儲對象也會越來越大,那么占用的內(nèi)存就會越來越多

勢必要減少一些不必要的存儲,所有只有純文本的靜態(tài)根節(jié)點(diǎn)就被排除了

2 多層函數(shù)調(diào)用

這個問題涉及到 render 和 靜態(tài) render 的合作

舉個例子

一個動態(tài)跟靜態(tài)混合的模板

生成的 render 函數(shù)是這樣的

with(this) {    
    return _c('div', [
        _m(0),
        ( testStaticRender) ? _c('span') : _e()
    ])
}

看到 _m(0) 了嗎,這個函數(shù)就是去獲取靜態(tài)模板的

這樣,靜態(tài)模板的處理

就多了一個 _m 函數(shù)的調(diào)用,加上初期涉及到了很多函數(shù)的處理,其中包括上一步的存儲

再者,既然純文本節(jié)點(diǎn)不做優(yōu)化

那么就是說更新時需要比對這部分嘍?

但是純文本的比對,就是直接 比較字符串 是否相等而已啊

消耗簡直不要太小,那么這樣,我還有必要去維護(hù)多一個靜態(tài)模板緩存嗎?

綜上所述

只有純文本子節(jié)點(diǎn)最好不要當(dāng)做靜態(tài)模板處理

以上只是個人的意淫想法,如有不同意見可以提出

番外疑惑

我不禁疑惑到,難道只有一個普通標(biāo)簽子節(jié)點(diǎn)的時候,好處難道會大一些嗎?

可以看到模板放在了 staticRenderFns 上,做了靜態(tài)模板處理

結(jié)果論出發(fā)的話,可能消耗的確大一些吧哈哈哈

更新的時候,會比較 div 和 span 和 span 內(nèi)的純文本

以上就是vue原理Compile之optimize標(biāo)記靜態(tài)節(jié)點(diǎn)源碼示例的詳細(xì)內(nèi)容,更多關(guān)于Compile optimize標(biāo)記靜態(tài)節(jié)點(diǎn)的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 詳解在vue-cli中引用jQuery、bootstrap以及使用sass、less編寫css

    詳解在vue-cli中引用jQuery、bootstrap以及使用sass、less編寫css

    這篇文章主要介紹了詳解在vue-cli中引用jQuery、bootstrap以及使用sass、less編寫css,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • 一文詳解WebStorm如何調(diào)試Vue項目

    一文詳解WebStorm如何調(diào)試Vue項目

    這篇文章主要介紹了如何使用WebStorm進(jìn)行斷點(diǎn)調(diào)試,包括配置、啟動本地應(yīng)用程序、設(shè)置斷點(diǎn)以及使用調(diào)試工具等步驟,文中通過圖文及代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-02-02
  • Vue中組件(Component)和插件(Plugin)的區(qū)別及說明

    Vue中組件(Component)和插件(Plugin)的區(qū)別及說明

    這篇文章主要介紹了Vue中組件(Component)和插件(Plugin)的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • element-ui table span-method(行合并)的實現(xiàn)代碼

    element-ui table span-method(行合并)的實現(xiàn)代碼

    element-ui官網(wǎng)中關(guān)于行合并的例子是根據(jù)行號進(jìn)行合并的,這顯然不符合我們?nèi)粘i_發(fā)需求,因為通常我們table中的數(shù)據(jù)都是動態(tài)生成的,非常具有實用價值,需要的朋友可以參考下
    2018-12-12
  • vue.js實現(xiàn)格式化時間并每秒更新顯示功能示例

    vue.js實現(xiàn)格式化時間并每秒更新顯示功能示例

    這篇文章主要介紹了vue.js實現(xiàn)格式化時間并每秒更新顯示功能,結(jié)合實例形式分析了vue.js時間格式化顯示與基于定時器進(jìn)行實時更新的相關(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • vue3中虛擬dom的介紹與使用詳解

    vue3中虛擬dom的介紹與使用詳解

    Vue?是如何將一份模板轉(zhuǎn)換為真實的?DOM?節(jié)點(diǎn)的,又是如何高效地更新這些節(jié)點(diǎn)的呢,這些都離不開虛擬dom這個概念,下面我們就來了解下虛擬dom這個概念以及它是什么吧
    2024-01-01
  • vue使用keep-alive進(jìn)行組件緩存方法詳解(組件不緩存問題解決)

    vue使用keep-alive進(jìn)行組件緩存方法詳解(組件不緩存問題解決)

    keep-alive包裹動態(tài)組件時,會緩存不活動的組件實例,而不是銷毀它們,下面這篇文章主要給大家介紹了關(guān)于vue使用keep-alive進(jìn)行組件緩存方法(組件不緩存問題解決)的相關(guān)資料,需要的朋友可以參考下
    2022-09-09
  • Vue.js 60分鐘快速入門教程

    Vue.js 60分鐘快速入門教程

    vuejs是當(dāng)下很火的一個JavaScript MVVM庫,它是以數(shù)據(jù)驅(qū)動和組件化的思想構(gòu)建的。今天給大家分享一篇教程關(guān)于Vue.js 60分鐘快速入門教程,一起看看吧
    2017-03-03
  • vue監(jiān)聽瀏覽器的后退和刷新事件,阻止默認(rèn)的事件方式

    vue監(jiān)聽瀏覽器的后退和刷新事件,阻止默認(rèn)的事件方式

    這篇文章主要介紹了vue監(jiān)聽瀏覽器的后退和刷新事件,阻止默認(rèn)的事件方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • vue過濾器用法實例分析

    vue過濾器用法實例分析

    這篇文章主要介紹了vue過濾器用法,結(jié)合實例形式總結(jié)分析了vue.js常見過濾器相關(guān)使用技巧與操作注意事項,需要的朋友可以參考下
    2019-03-03

最新評論

延津县| 盐源县| 上杭县| 益阳市| 全州县| 宿迁市| 库车县| 崇仁县| 营口市| 淮阳县| 嘉义县| 天津市| 湖州市| 抚松县| 宜宾县| 红河县| 峨眉山市| 锡林郭勒盟| 福泉市| 花莲县| 嫩江县| 福清市| 自治县| 扶风县| 西安市| 漳浦县| 桐柏县| 故城县| 渝中区| 桦甸市| 行唐县| 扎囊县| 枣庄市| 宝清县| 凌云县| 壶关县| 靖边县| 克山县| 海南省| 韩城市| 阜新|