寫文章不容易,點個讚唄兄弟node
專一 Vue 源碼分享,文章分爲白話版和 源碼版,白話版助於理解工做原理,源碼版助於瞭解內部詳情,讓咱們一塊兒學習吧數組
研究基於 Vue版本 【2.5.17】緩存
若是你以爲排版難看,請點擊 下面連接 或者 拉到 下面關注公衆號也能夠吧性能優化
【Vue原理】Render - 源碼版 之 靜態 Render 函數
上一篇咱們講了 render 函數,而 Vue 爲了更新時速度快一些,加入了一個 staticRender性能
沒錯,就是 靜態 render,看過前面文章的人,應該知道什麼是 靜態 render學習
靜態 render 就是用於渲染哪些不會變化的節點優化
你們能夠先看看,Vue 是怎麼判斷某個節點是不是靜態節點this
好,下面開始咱們的正文,想了想,咱們仍是以幾個問題開始吧
一、靜態 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 咱們就講完了,是否是很簡單,在沒看源碼以前,我覺得很難
如今看完,發現也簡單的,不過我也是看了幾個月的。。。。
鑑於本人能力有限,不免會有疏漏錯誤的地方,請你們多多包涵,若是有任何描述不當的地方,歡迎後臺聯繫本人,有重謝