【Vue原理】Render - 源碼版 之 靜態 Render

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

專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧數組

研究基於 Vue版本 【2.5.17】緩存

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

【Vue原理】Render - 源碼版 之 靜態 Render bash

上一篇咱們講了 render 函數,而 Vue 爲了更新時速度快一些,加入了一個 staticRender函數

沒錯,就是 靜態 render,看過前面文章的人,應該知道什麼是 靜態 render性能

靜態 render 就是用於渲染哪些不會變化的節點學習

你們能夠先看看,Vue 是怎麼判斷某個節點是不是靜態節點優化

Compile 之 optimize 標記靜態節點 ui

好,下面開始咱們的正文,想了想,咱們仍是以幾個問題開始吧

一、靜態 render 是什麼樣子的

二、靜態 render 是怎麼生成和 保存

三、靜態 render 怎麼執行


什麼是 靜態Render

靜態 render 其實跟 render 是同樣的,都是執行獲得 Vnode

只是靜態 render,沒有綁定動態數據而已,也就是說不會變化

好比說,一個簡單 render 是這樣的

公衆號

綁定了動態數據,須要從實例去獲取

_c('div',[_v(_s(aa))])
複製代碼

而靜態 render 是這樣的

公衆號

沒有動態數據,這個靜態render 的執行結果是永遠不會變的

_c('div',[_c('span',[_v("1")])])
複製代碼

生成保存靜態Render

靜態 render 是在 generate 階段生成的,生成的方式和 render 是同樣的

好比在一個模板中,有不少個靜態 根節點,像這樣

公衆號

首先,Vue 會在遍歷模板的時候,發現 span 和 strong 自己以及其子節點都是靜態的

那麼就會給 span 和 strong 節點自己設置一個屬性 staticRoot,表示他們是靜態根節點

而後這兩個靜態根節點就會生成本身專屬的 靜態 render

如何標記靜態根節點的具體能夠看 Compile 之 optimize 標記靜態節點

怎麼把靜態根節點生成 render 的能夠看 Compile 之 generate 節點拼接 中 genStatic 的部分

若是你有一直看個人Vue 筆記的話,你應該這裏是會有點印象的

以後

靜態 render 生成以後是須要保存的,那麼保存在哪裏呢?

保存在一個數組中,名叫 staticRenderFns,就是直接push 進去

固然了,此時的 push 進去的 靜態 render 仍是字符串,並無變成函數

以上面的模板爲例,這裏的 staticRenderFns 就是這樣,包含了兩個字符串

staticRenderFns  = [
    "_c('span',[_c('b',[_v("1")])])",    

    "_c('strong',[_c('b',[_v("1")])])"

]
複製代碼

可是在後面會逐個遍歷變成可執行的函數

staticRenderFns = staticRenderFns.map(code => {    

    return new Function(code)

});
複製代碼

那麼 這個 staticRenderFns 又是什麼啊?

每一個 Vue 實例都有一個獨立的 staticRenderFns,用來保存實例自己的靜態 render

staticRenderFns 的位置是

vm.$options.staticRenderFns

公衆號


執行靜態Render

靜態 render 須要配合 render 使用,怎麼說

看個例子

公衆號

這個模板的 render 函數是

_c('div',[ 
    _m(0), 
    _v(_s(a), 
    _m(1) 
])
複製代碼

_m(0) , _m(1) 就是執行的就是 靜態 render 函數,而後返回 Vnode

因而 render 也能夠完成 vnode 樹的構建了

那麼 _m 是什麼呢?

在 Vue 初始化時,給Vue的原型便註冊了這個函數,也就是說每一個實例都繼承到 _m

function installRenderHelpers(target) {
    target._m = renderStatic;
}



installRenderHelpers(Vue.prototype);
複製代碼

再來看 renderStatic

function renderStatic(index) {    



    var cached = this._staticTrees || (this._staticTrees = []);    

    var tree = cached[index];  

     

    // 若是緩存存在,就直接返回
    if (tree) return tree    



    // 這裏是執行 render 的地方

    tree = cached[index] =

        this.$options.staticRenderFns[index].call(

            this, null, this 

        );

   

    // 只是標記靜態 和 節點id 而已
    markStatic(tree, "__static__" + index, false);    



    return tree

}
複製代碼

這個函數作的事情能夠分爲幾件

一、執行靜態render

二、緩存靜態render 結果

三、標記 靜態 render 執行獲得的 Vnode

咱們來一個個說

1 執行靜態render

上面咱們說過了,靜態render 保存在 數組 staticRenderFns

因此這個函數接收一個索引值,表示要執行數組內哪一個靜態render

取出靜態render 後,執行並綁定 Vue 實例爲上下文對象

而後獲得 Vnode

2 緩存靜態render 結果

這一步就是要把上一步獲得的 Vnode 緩存起來

那麼緩存在哪裏呢?

_staticTrees

這是一個數組,每一個實例都會有一個獨立的 _staticTrees,用來存在自身的靜態 render 執行獲得的 Vnode

看一下上個模板中實例保存的 _staticTrees

公衆號

3 標記 靜態 render 執行獲得的 Vnode

咱們已經執行靜態render獲得了 Vnode,這一步目的是標記

標記什麼呢

一、添加標誌位 isStatic

二、添加 Vnode 惟一id

renderStatic 中咱們看到標記的時候,調用了 markStatic 方法,如今就來看看

function markStatic(
    tree, key

) {    



    if (Array.isArray(tree)) {        



        for (var i = 0; i < tree.length; i++) {            



            if ( tree[i] && typeof tree[i] !== 'string') {                



                var node  = tree[i]


                node.isStatic = true;
                node.key = key + "_" + i;
            }
        }
    }
    else {

        tree.isStatic = true;
        tree.key = key
    }
}
複製代碼

爲何添加標誌位 isStatic?

前面咱們添加的全部靜態標誌位都是針對 模板生成的 ast

這裏咱們是給 Vnode 添加 isStatic,這才能完成Vue的目的

Vue 目的就是性能優化,在頁面改變時,能儘可能少的更新節點

因而在頁面變化時,當 Vue 檢測到該 Vnode.isStatic = true,便不會比較這部份內容

從而減小比對時間

Vnode 惟一id

每一個靜態根Vnode 都會存在的一個屬性

公衆號

我也沒想到 靜態Vnode 的 key 有什麼做用,畢竟不須要比較,也許是易於區分??

最後

靜態 render 咱們就講完了,是否是很簡單,在沒看源碼以前,我覺得很難

如今看完,發現也簡單的,不過我也是看了幾個月的。。。。

鑑於本人能力有限,不免會有疏漏錯誤的地方,請你們多多包涵,若是有任何描述不當的地方,歡迎後臺聯繫本人,有重謝

公衆號
相關文章
相關標籤/搜索