寫文章不容易,點個讚唄兄弟專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧node
研究基於 Vue版本 【2.5.17】數組
若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧緩存
【Vue原理】Render - 源碼版 之 靜態 Render 性能優化
上一篇咱們講了 render 函數,而 Vue 爲了更新時速度快一些,加入了一個 staticRender函數
沒錯,就是 靜態 render,看過前面文章的人,應該知道什麼是 靜態 render性能
靜態 render 就是用於渲染哪些不會變化的節點學習
你們能夠先看看,Vue 是怎麼判斷某個節點是不是靜態節點優化
Compile 之 optimize 標記靜態節點 this
好,下面開始咱們的正文,想了想,咱們仍是以幾個問題開始吧 spa
一、靜態 render 是什麼樣子的
二、靜態 render 是怎麼生成和 保存
三、靜態 render 怎麼執行
靜態 render 其實跟 render 是同樣的,都是執行獲得 Vnode
只是靜態 render,沒有綁定動態數據而已,也就是說不會變化
好比說,一個簡單 render 是這樣的
綁定了動態數據,須要從實例去獲取
_c('div',[_v(_s(aa))])
而靜態 render 是這樣的
沒有動態數據,這個靜態render 的執行結果是永遠不會變的
_c('div',[_c('span',[_v("1")])])
靜態 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 函數是
_c('div',[ _m(0), _v(_s(a), _m(1) ])
_m(0) , _m(1) 就是執行的就是 靜態 render 函數,而後返回 Vnode
因而 render 也能夠完成 vnode 樹的構建了
在 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
咱們來一個個說
上面咱們說過了,靜態render 保存在 數組 staticRenderFns
因此這個函數接收一個索引值,表示要執行數組內哪一個靜態render
取出靜態render 後,執行並綁定 Vue 實例爲上下文對象
而後獲得 Vnode
這一步就是要把上一步獲得的 Vnode 緩存起來
那麼緩存在哪裏呢?
_staticTrees
這是一個數組,每一個實例都會有一個獨立的 _staticTrees,用來存在自身的靜態 render 執行獲得的 Vnode
看一下上個模板中實例保存的 _staticTrees
咱們已經執行靜態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 } }
前面咱們添加的全部靜態標誌位都是針對 模板生成的 ast
這裏咱們是給 Vnode 添加 isStatic,這才能完成Vue的目的
Vue 目的就是性能優化,在頁面改變時,能儘可能少的更新節點
因而在頁面變化時,當 Vue 檢測到該 Vnode.isStatic = true,便不會比較這部份內容
從而減小比對時間
每一個靜態根Vnode 都會存在的一個屬性
我也沒想到 靜態Vnode 的 key 有什麼做用,畢竟不須要比較,也許是易於區分??
靜態 render 咱們就講完了,是否是很簡單,在沒看源碼以前,我覺得很難
如今看完,發現也簡單的,不過我也是看了幾個月的。。。。
鑑於本人能力有限,不免會有疏漏錯誤的地方,請你們多多包涵,若是有任何描述不當的地方,歡迎後臺聯繫本人,有重謝