【Vue原理】Compile - 白話版

寫文章不容易,點個讚唄兄弟


專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧
研究基於 Vue版本 【2.5.17】

若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧node

【Vue原理】Compile - 白話版 數組

終於到了要講 compile 白話的時候了,你們準備好了嗎,白話版確定不會很複雜啦,源碼版就不必定了。。。性能優化

源碼版我寫了9篇啊!每篇的篇幅都很長啊!!我都快寫奔潰了啊!!函數

都快堅持不下來了,我算了算, compile 的源碼版,我好像快寫了一個多月???性能

臥槽,居然寫了這麼久.....學習

公衆號

好吧,如今開始咱們的正文優化


Compile

compile 的內容很是多,大體分爲三塊主要內容,我也稱他們是Vue的 渲染三巨頭spa

就是 parse,optimize,generate3d

雖然分爲三塊,可是要明確一點code

compile 的做用是解析模板,生成渲染模板的 render

好比這樣的模板

公衆號

通過 compile 以後,就會生成下面的 render

_c('div', [_c('span'), _v(num)])

而 render 的做用,也是爲了生成跟模板節點一一對應的 Vnode

{    

    tag: "div",    

    children:[{        

        tag: "span",        

        text: undefined

    },{        

        tag: undefined

        text: "111"
    }]
}

下面咱們就來一個個看渲染三巨頭


Parse

這是 compile 的第一個步驟

做用是

接收 template 原始模板,按照模板的節點 和數據 生成對應的 ast

好比這樣

公衆號

生成的 ast 是這樣,全部模板中出現的數據,你均可以在 ast 中找到

{    

    tag: "div",    

    attrsMap: {test: "2"},    

    children:[{        

        tag: "span",        

        children: [],        

        attrsMap: {name: "1"}

    }]
}

ast 是什麼?我的簡單理解的話

以數據的形式去描述一個東西的全部的特徵吧,說錯別打我

好比說ast 描述我

{    

    name: "神仙朱",    

    sex: 1,

    desc: "一個靚仔"

}

具體能夠查一下,相關內容挺多的

另外,這裏不會講細節,parse 是怎麼生成 ast 的,由於涉及不少源碼,放在源碼版了


Optimize

這是 compile 的第二步

做用是

遍歷遞歸每個ast節點,標記靜態的節點(沒有綁定任何動態數據),

這樣就知道那部分不會變化,因而在頁面須要更新時,減小去比對這部分DOM

從而達到性能優化的目的

好比這個模板

公衆號

span 和 b 就是靜態節點,在 optimize 處理中,就會給他們添加 static 判斷是不是靜態節點

{    

    static: false,    

    staticRoot: false,    

    tag: "div",    

    children: [{        

        staticRoot: true,        

        tag: "span",        

        children: [{            

            static: true,            

            tag: "b"

        }]
    },{        

        static: false,        

        text: "{{a}}"

    }]
}

而你也看到一個屬性,staticRoot,這個是表示這個節點是不是靜態根節點的意思

用來標記 某部分靜態節點 最大的祖宗節點,後面更新的時候,只要碰到這個屬性,就知道他的全部子孫節點都是靜態節點了,而不須要每一個子孫節點都要判斷一次浪費時間

具體是怎麼作的,感興趣的話歡迎看之後的源碼版


Generate

這是 compile 的第三步

做用是

把前兩步生成完善的 ast 組裝成 render 字符串(這個 render 變成函數後是可執行的函數,不過如今是字符串的形態,後面會轉成函數)

看個例子

公衆號

通過前兩步變成 ast

{    

    static: false,    

    staticRoot: false,    

    tag: "div",    

    children: [{        

        static: false,        

        staticRoot: false,        

        tag: "span",        

        children: [{            

            static: false,            

            text: "{{b}}"

        }]
    },{        

        static: false,        

        text: "{{a}}"

    }]
}

而後,generate 接收 ast,先處理最外層 ast,而後開始遞歸遍歷子節點,直到全部節點被處理完

這個過程當中,字符串會被一點一點拼接完成,好比上面的 ast 拼接結果就是下面這樣

_c 是生成節點對應的 Vnode 的一個函數

`
_c('div', [
    _c('span', [
        _v(b)
    ]),
    _v(a)
])
`

簡單說一下拼接流程

一、一開始接收到 ast,處理最外層 ast 這個點,是 div,因而拼接獲得字符串

code  = ` _c('div', [  `

二、遍歷 div 子節點,遇到 span,拼接在 div 的子節點數組中

code = `_c('div', [  _c('span', [ `

三、開始處理 span 的子節點 b,放進 span 的 子節點數組中

code = ` _c('div', [  _c('span', [  _v(b)  `

四、span 子節點處理完,閉合 span 的 子節點數組

code = ` _c('div', [  _c('span', [  _v(b) ] `

五、繼續處理 span 同級 的子節點,是個文本節點,可是是動態值,變量是 a

code = `_c('div', [  _c('span', [  _v(b) ] , _v(a)  `

六、全部子節點都處理完畢,閉合 div 的 子節點數組

code = ` _c('div', [  _c('span', [  _v(b) ] , _v(a) )]  `

render轉成函數

前面兩步把 template 解析生成了 render 字符串,可是須要執行的話,仍是須要轉換成函數的

怎麼轉呢?就是下面這樣

render = new Function(render)

而後 render 保存在實例上,具體位置是

公衆號

vm.$options.render

至此,compile 全部的功能就完成了

而關於 render 的內容,好比說 render 中出現的各類函數是什麼,會專門放在 render 的文章去記錄

公衆號

公衆號

相關文章
相關標籤/搜索