欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Vue編譯優(yōu)化實(shí)現(xiàn)流程詳解

 更新時(shí)間:2023年01月28日 15:57:05   作者:volit_  
編譯優(yōu)化指的是編譯器將模板編譯為渲染函數(shù)的過(guò)程中,盡可能多的提取關(guān)鍵信息,并以此指導(dǎo)生成最優(yōu)代碼的過(guò)程,優(yōu)化的方向主要是區(qū)分動(dòng)態(tài)內(nèi)容和靜態(tài)內(nèi)容,并針對(duì)不同的內(nèi)容采用不同的優(yōu)化策略

動(dòng)態(tài)節(jié)點(diǎn)收集與補(bǔ)丁標(biāo)志

1.傳統(tǒng)diff算法的問(wèn)題

對(duì)于一個(gè)普通模板文件,如果只是標(biāo)簽中的內(nèi)容發(fā)生了變化,那么最簡(jiǎn)單的更新方法很明顯是直接替換標(biāo)簽中的文本內(nèi)容。但是diff算法很明顯做不到這一點(diǎn),它會(huì)重新生成一棵虛擬DOM樹(shù),然后對(duì)兩棵虛擬DOM樹(shù)進(jìn)行比較。很明顯,與直接替換標(biāo)簽中的內(nèi)容相比,傳統(tǒng)diff算法需要做很多無(wú)意義的操作,如果能夠去除這些無(wú)意義的操作,將會(huì)省下一筆很大的性能開(kāi)銷(xiāo)。其實(shí),只要在模板編譯時(shí),標(biāo)記出哪些節(jié)點(diǎn)是動(dòng)態(tài)的,哪些是靜態(tài)的,然后再通過(guò)虛擬DOM傳遞給渲染器,渲染器就能根據(jù)這些信息,直接修改對(duì)應(yīng)節(jié)點(diǎn),從而提高運(yùn)行時(shí)性能。

2.Block和PatchFlags

對(duì)于一個(gè)傳統(tǒng)的模板:

<div>
    <div>
        foo
    </div>
    <p>
        {{ bar }}
    </p>
</div>

在這個(gè)模板中,只用{{ bar }}是動(dòng)態(tài)內(nèi)容,因此在bar變量發(fā)生變化時(shí),只需要修改p標(biāo)簽內(nèi)的內(nèi)容就行了。因此我們?cè)谶@個(gè)模板對(duì)于的虛擬DOM中,加入patchFlag屬性,以此來(lái)標(biāo)簽?zāi)0逯械膭?dòng)態(tài)內(nèi)容。

const vnode = {
    tag: 'div',
    children: [
        { tag: 'div', children: 'foo' },
        { tag: 'p', children: ctx.bar, patchFlag: 1 },
    ]
}

對(duì)于不同的數(shù)值綁定,我們分別用不同的patch值來(lái)表示:

  • 數(shù)字1,代表節(jié)點(diǎn)有動(dòng)態(tài)的textContent
  • 數(shù)字2,代表節(jié)點(diǎn)有動(dòng)態(tài)的class綁定
  • 數(shù)字3,代表節(jié)點(diǎn)有動(dòng)態(tài)的style綁定
  • 數(shù)字4,其他…

我們可以新建一個(gè)枚舉類(lèi)型來(lái)表示這些值:

enum PatchFlags {
    TEXT: 1,
    CLASS,
    STYLE,
    OTHER
}

這樣我們就在虛擬DOM的創(chuàng)建階段,將動(dòng)態(tài)節(jié)點(diǎn)提取出來(lái):

const vnode = {
    tag: 'div',
    children: [
        { tag: 'div', children: 'foo' },
        { tag: 'p', children: ctx.bar, patchFlag: PatchFlags.TEXT },
    ],
    dynamicChildren: [
        { tag: 'p', children: ctx.bar, patchFlag: PatchFlags.TEXT },
    ]
}

3.收集動(dòng)態(tài)節(jié)點(diǎn)

首先我們創(chuàng)建收集動(dòng)態(tài)節(jié)點(diǎn)的邏輯。

const dynamicChildrenStack = []; // 動(dòng)態(tài)節(jié)點(diǎn)棧
let currentDynamicChildren = null; // 當(dāng)前動(dòng)態(tài)節(jié)點(diǎn)集合
function openBlock() {
    // 創(chuàng)建一個(gè)新的動(dòng)態(tài)節(jié)點(diǎn)棧
	dynamicChildrenStack.push((currentDynamicChildren = []));
}
function closeBlock() {
    // openBlock創(chuàng)建的動(dòng)態(tài)節(jié)點(diǎn)集合彈出
    currentDynamicChildren = dynamicChildrenStack.pop();
}

然后,我們?cè)趧?chuàng)建虛擬節(jié)點(diǎn)的時(shí)候,對(duì)動(dòng)態(tài)節(jié)點(diǎn)進(jìn)行收集。

function createVNode(tag, props, children, flags) {
    const key = props && props.key;
    props && delete props.key;
    const vnode = {
        tag,
        props,
        children,
        key,
        patchFlags: flags
    }
    if(typeof flags !== 'undefined' && currentDynamicChildren) {
        currentDynamicChildren.push(vnode);
    }
    return vnode;
}

然后我們修改組件渲染函數(shù)的邏輯。

render() {
    return (openBlock(), createBlock('div', null, [
        createVNode('p', { class: 'foo' }, null, 1),
        createVNode('p', { class: 'bar' }, null)
    ]));
}
function createBlock(tag, props, children) {
    const block = createVNode(tag, props, children);
    block.dynamicChildren = currentDynamicChildren;
    closeBlock();
    return block;
}

4.渲染器運(yùn)行時(shí)支持

function patchElement(n1, n2) {
    const el = n2.el = n1.el;
    const oldProps = n1.props;
    const newProps = n2.props;
    // ...
    if(n2.dynamicChildren) {
        // 如果有動(dòng)態(tài)節(jié)點(diǎn)數(shù)組,直接更新動(dòng)態(tài)節(jié)點(diǎn)數(shù)組
        patchBlockChildren(n1, n2);
    } else {
        patchChildren(n1, n2, el);
    }
}
function pathcBlockChildren(n1, n2) {
    for(let i = 0; i < n2.dynamicChildren.length; i++) {
        patchElement(n1.dynamicChildren[i], n2.dynamicChildren[i]);
    }
}

由于我們標(biāo)記了不同的動(dòng)態(tài)節(jié)點(diǎn)類(lèi)型,因此我們可以針對(duì)性的完成靶向更新。

function patchElement(n1, n2) {
    const el = n2.el = n1.el;
    const oldProps = n1.props;
    const newProps = n2.props;
    if(n2.patchFlags) {
        if(n2.patchFlags === 1) {
            // 只更新內(nèi)容
        } else if(n2.patchFlags === 2) {
            // 只更新class
        } else if(n2.patchFlags === 3) {
            // 只更新style
        } else {
            // 更新所有
            for(const k in newProps) {
                if(newProps[key] !== oldProps[key]) {
                	patchProps(el, key, oldProps[k], newProps[k]);
                }
            }
            for(const k in oldProps) {
                if(!key in newProps) {
                    patchProps(el, key, oldProps[k], null);
                }
            }
        }
    }
    patchChildren(n1, n2, el);
}

5.Block樹(shù)

組件的根節(jié)點(diǎn)必須作為Block角色,這樣,從根節(jié)點(diǎn)開(kāi)始的所有動(dòng)態(tài)子代節(jié)點(diǎn)都會(huì)被收集到根節(jié)點(diǎn)的dynamicChildren數(shù)組中。除了根節(jié)點(diǎn)外,帶有v-if、v-for這種結(jié)構(gòu)化指令的節(jié)點(diǎn),也會(huì)被作為Block角色,這些Block角色共同構(gòu)成一棵Block樹(shù)。

靜態(tài)提升

假設(shè)有以下模板

<div>
    <p>
        static text
    </p>
    <p>
        {{ title }}
    </p>
</div>

默認(rèn)情況下,對(duì)應(yīng)的渲染函數(shù)為:

function render() {
    return (openBlock(), createBlock('div', null, [
        createVNode('p', null, 'static text'),
        createVNode('p', null, ctx.title, 1 /* TEXT */)
    ]))
}

在這段代碼中,當(dāng)ctx.title屬性變化時(shí),內(nèi)容為靜態(tài)文本的p標(biāo)簽節(jié)點(diǎn)也會(huì)跟著渲染一次,這很明顯式不必要的。因此,我們可以使用“靜態(tài)提升”,即將靜態(tài)節(jié)點(diǎn),提取到渲染函數(shù)之外,這樣渲染函數(shù)在執(zhí)行的時(shí)候,只是保持了對(duì)靜態(tài)節(jié)點(diǎn)的引用,而不會(huì)重新創(chuàng)建虛擬節(jié)點(diǎn)。

const hoist1 = createVNode('p', null, 'static text');
function render() {
    return (openBlock(), createBlock('div', null, [
        hoist1,
        createVNode('p', null, ctx.title, 1 /* TEXT */)
    ]))
}

除了靜態(tài)節(jié)點(diǎn),對(duì)于靜態(tài)props我們也可以將其進(jìn)行靜態(tài)提升處理。

const hoistProps = { foo: 'bar', a: '1' };
function render() {
    return (openBlock(), createBlock('div', null, [
        hoist1,
        createVNode('p', hoistProps, ctx.title, 1 /* TEXT */)
    ]))
}

預(yù)字符化

除了對(duì)節(jié)點(diǎn)進(jìn)行靜態(tài)提升外,我們還可以對(duì)于純靜態(tài)的模板進(jìn)行預(yù)字符化。對(duì)于這樣一個(gè)模板:

<templete>
	<p></p>
    <p></p>
    <p></p>
    <p></p>
    <p></p>
    ...
    <p></p>
    <p></p>
    <p></p>
    <p></p>
</templete>

我們完全可以將其預(yù)處理為:

const hoistStatic = createStaticVNode('<p></p><p></p><p></p><p></p>...<p></p><p></p><p></p><p></p>');
render() {
    return (openBlock(), createBlock('div', null, [
		hoistStatic
    ]));
}

這么做的優(yōu)勢(shì):

  • 大塊的靜態(tài)內(nèi)容可以通過(guò)innerHTML直接設(shè)置,在性能上具有一定優(yōu)勢(shì)
  • 減少創(chuàng)建虛擬節(jié)點(diǎn)帶來(lái)的額外開(kāi)銷(xiāo)
  • 減少內(nèi)存占用

緩存內(nèi)聯(lián)事件處理函數(shù)

當(dāng)為組件添加內(nèi)聯(lián)事件時(shí),每次新建一個(gè)組件,都會(huì)為該組件重新創(chuàng)建并綁定一個(gè)新的內(nèi)聯(lián)事件函數(shù),為了避免這方面的無(wú)意義開(kāi)銷(xiāo),我們可以對(duì)內(nèi)聯(lián)事件處理函數(shù)進(jìn)行緩存。

function render(ctx, cache) {
    return h(Comp, {
        onChange: cache[0] || cache[0] = ($event) => (ctx.a + ctx.b);
    })
}

v-once

v-once指令可以是組件只渲染一次,并且即使該組件綁定了動(dòng)態(tài)參數(shù),也不會(huì)更新。它與內(nèi)聯(lián)事件一樣,也是使用了緩存,同時(shí)通過(guò)setBlockTracking(-1)阻止該VNode被Block收集。

v-once的優(yōu)點(diǎn):

  • 避免組件更新時(shí)重新創(chuàng)建虛擬DOM帶來(lái)的性能開(kāi)銷(xiāo)
  • 避免無(wú)用的Diff開(kāi)銷(xiāo)

到此這篇關(guān)于Vue編譯優(yōu)化實(shí)現(xiàn)流程詳解的文章就介紹到這了,更多相關(guān)Vue編譯優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Vue實(shí)現(xiàn)頁(yè)面添加滿(mǎn)屏水印和去除水印功能

    Vue實(shí)現(xiàn)頁(yè)面添加滿(mǎn)屏水印和去除水印功能

    在一些特殊的應(yīng)用場(chǎng)景中,可能需要在網(wǎng)頁(yè)上添加水印以保護(hù)版權(quán)或標(biāo)識(shí)信息,本文將介紹如何在Vue項(xiàng)目中添加滿(mǎn)屏水印并實(shí)現(xiàn)去除水印的功能,文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-07-07
  • Vue?h函數(shù)的使用詳解

    Vue?h函數(shù)的使用詳解

    本文主要介紹了Vue?h函數(shù)的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Vuex的store中的Module用法及說(shuō)明

    Vuex的store中的Module用法及說(shuō)明

    這篇文章主要介紹了Vuex的store中的Module用法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2023-01-01
  • vue中setup語(yǔ)法糖寫(xiě)法實(shí)例

    vue中setup語(yǔ)法糖寫(xiě)法實(shí)例

    如果你在 vue3 開(kāi)發(fā)中使用了語(yǔ)法的話,對(duì)于組件的name屬性,需要做一番額外的處理,下面這篇文章主要給大家介紹了關(guān)于Vue3 setup語(yǔ)法糖的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 解決新建一個(gè)vue項(xiàng)目過(guò)程中遇到的問(wèn)題

    解決新建一個(gè)vue項(xiàng)目過(guò)程中遇到的問(wèn)題

    這篇文章主要介紹了解決新建一個(gè)vue項(xiàng)目過(guò)程中遇到的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-10-10
  • Vuex數(shù)據(jù)持久化實(shí)現(xiàn)的思路與代碼

    Vuex數(shù)據(jù)持久化實(shí)現(xiàn)的思路與代碼

    Vuex數(shù)據(jù)持久化可以很好的解決全局狀態(tài)管理,當(dāng)刷新后數(shù)據(jù)會(huì)消失,這是我們不愿意看到的。這篇文章主要給大家介紹了關(guān)于Vuex數(shù)據(jù)持久化實(shí)現(xiàn)的思路與代碼,需要的朋友可以參考下
    2021-05-05
  • Vue3.0實(shí)現(xiàn)圖片預(yù)覽組件(媒體查看器)功能

    Vue3.0實(shí)現(xiàn)圖片預(yù)覽組件(媒體查看器)功能

    最近項(xiàng)目中有個(gè)場(chǎng)景,一組圖片、視頻、音頻、文件數(shù)據(jù),要求點(diǎn)擊圖片可以放大預(yù)覽,左右可以切換音視頻、文件,支持鼠標(biāo)及各種鍵控制?縮放,左右旋轉(zhuǎn),移動(dòng)等功能,這篇文章主要介紹了Vue3.0實(shí)現(xiàn)圖片預(yù)覽組件(媒體查看器),需要的朋友可以參考下
    2023-12-12
  • vue常用的數(shù)字孿生可視化的自適應(yīng)方案

    vue常用的數(shù)字孿生可視化的自適應(yīng)方案

    這篇文章主要為大家介紹了vue常用的數(shù)字孿生可視化的自適應(yīng)方案詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • vue中watch和computed的區(qū)別與使用方法

    vue中watch和computed的區(qū)別與使用方法

    這篇文章主要給大家介紹了關(guān)于vue中watch和computed的區(qū)別與使用方法的相關(guān)資料,文中通過(guò)實(shí)例代碼結(jié)束的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • vue框架編輯接口頁(yè)面下拉級(jí)聯(lián)選擇并綁定接口所屬模塊

    vue框架編輯接口頁(yè)面下拉級(jí)聯(lián)選擇并綁定接口所屬模塊

    這篇文章主要為大家介紹了vue框架編輯接口頁(yè)面實(shí)現(xiàn)下拉級(jí)聯(lián)選擇以及綁定接口所屬模塊,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05

最新評(píng)論