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

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

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

動態(tài)節(jié)點收集與補丁標(biāo)志

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

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

2.Block和PatchFlags

對于一個傳統(tǒng)的模板:

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

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

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

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

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

我們可以新建一個枚舉類型來表示這些值:

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

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

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.收集動態(tài)節(jié)點

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

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

然后,我們在創(chuàng)建虛擬節(jié)點的時候,對動態(tài)節(jié)點進行收集。

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.渲染器運行時支持

function patchElement(n1, n2) {
    const el = n2.el = n1.el;
    const oldProps = n1.props;
    const newProps = n2.props;
    // ...
    if(n2.dynamicChildren) {
        // 如果有動態(tài)節(jié)點數(shù)組,直接更新動態(tài)節(jié)點數(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)記了不同的動態(tài)節(jié)點類型,因此我們可以針對性的完成靶向更新。

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樹

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

靜態(tài)提升

假設(shè)有以下模板

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

默認情況下,對應(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屬性變化時,內(nèi)容為靜態(tài)文本的p標(biāo)簽節(jié)點也會跟著渲染一次,這很明顯式不必要的。因此,我們可以使用“靜態(tài)提升”,即將靜態(tài)節(jié)點,提取到渲染函數(shù)之外,這樣渲染函數(shù)在執(zhí)行的時候,只是保持了對靜態(tài)節(jié)點的引用,而不會重新創(chuàng)建虛擬節(jié)點。

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é)點,對于靜態(tài)props我們也可以將其進行靜態(tài)提升處理。

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

預(yù)字符化

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

<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)勢:

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

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

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

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

v-once

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

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

  • 避免組件更新時重新創(chuàng)建虛擬DOM帶來的性能開銷
  • 避免無用的Diff開銷

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

相關(guān)文章

  • 加載 vue 遠程代碼的組件實例詳解

    加載 vue 遠程代碼的組件實例詳解

    vue-cli 作為 Vue 官方推薦的項目構(gòu)建腳手架,它提供了開發(fā)過程中常用的,熱重載,構(gòu)建,調(diào)試,單元測試,代碼檢測等功能。我們本次的異步遠端組件將基于 vue-cli 開發(fā)
    2017-11-11
  • uniapp實現(xiàn)webview頁面關(guān)閉功能的代碼示例

    uniapp實現(xiàn)webview頁面關(guān)閉功能的代碼示例

    uniapp用web-view打開一個網(wǎng)頁,網(wǎng)頁中點擊跳轉(zhuǎn)到下一層級的網(wǎng)頁,一層層深入,點擊返回鍵或者頁面上方返回按鈕只能一層層往回退,下面這篇文章主要給大家介紹了關(guān)于uniapp實現(xiàn)webview頁面關(guān)閉功能的相關(guān)資料,需要的朋友可以參考下
    2024-03-03
  • vue backtop組件的實現(xiàn)完整代碼

    vue backtop組件的實現(xiàn)完整代碼

    這篇文章主要介紹了vue backtop組件的實現(xiàn)完整代碼,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-04-04
  • vue中使用vue-print.js實現(xiàn)多頁打印

    vue中使用vue-print.js實現(xiàn)多頁打印

    這篇文章主要介紹了vue中使用vue-print.js實現(xiàn)多頁打印,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Vue使用mockjs問題(返回數(shù)據(jù)、get、post 請求)

    Vue使用mockjs問題(返回數(shù)據(jù)、get、post 請求)

    這篇文章主要介紹了Vue使用mockjs問題(返回數(shù)據(jù)、get、post 請求),具有很好的參考價值,希望對大家有所幫助。
    2023-05-05
  • vue觀察模式淺析

    vue觀察模式淺析

    這篇文章主要介紹了vue觀察模式淺析,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • Ant Design Vue pro 動態(tài)路由的實現(xiàn)和打包方式

    Ant Design Vue pro 動態(tài)路由的實現(xiàn)和打包方式

    這篇文章主要介紹了Ant Design Vue pro 動態(tài)路由的實現(xiàn)和打包方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • VUE如何利用vue-print-nb實現(xiàn)打印功能詳解

    VUE如何利用vue-print-nb實現(xiàn)打印功能詳解

    這篇文章主要給大家介紹了關(guān)于VUE如何利用vue-print-nb實現(xiàn)打印功能的相關(guān)資料,文中還給大家介紹了vue-print-nb使用中的常見問題,如空白頁,需要的朋友可以參考下
    2022-04-04
  • echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸)

    echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸)

    這篇文章主要介紹了echarts實現(xiàn)獲取datazoom的起始值(包括x軸和y軸),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-07-07
  • 解決cordova+vue 項目打包成APK應(yīng)用遇到的問題

    解決cordova+vue 項目打包成APK應(yīng)用遇到的問題

    這篇文章主要介紹了解決cordova+vue 項目打包成APK應(yīng)用遇到的問題,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-05-05

最新評論

侯马市| 工布江达县| 喀什市| 广州市| 团风县| 璧山县| 铜川市| 临泉县| 古交市| 云南省| 双牌县| 沧州市| 贵州省| 娱乐| 惠水县| 姜堰市| 疏勒县| 沁水县| 蓬溪县| 容城县| 池州市| 巧家县| 盖州市| 尚志市| 阿坝县| 旬阳县| 新民市| 梅河口市| 江西省| 株洲市| 惠来县| 浦江县| 桐城市| 灵璧县| 轮台县| 延川县| 乐东| 女性| 裕民县| 高唐县| 巴马|