摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對值的認識介紹一下對于兼容的修改這篇主要是說一下的算法在上一篇中我總結過對比渲染的流程大體分為通過來判斷兩個是
總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新)
介紹一下snabbdom基本用法
介紹一下snabbdom渲染原理
介紹一下snabddom的diff算法和對key值的認識
介紹一下對于兼容IE8的修改
這篇主要是說一下snabbdom的diff算法
在上一篇中我總結過:
對比渲染的流程大體分為
1.通過sameVnode來判斷兩個vnode是否值得進行比較
2.如果不值得,直接刪除舊的vnode,渲染新的vnode
3.如果值得,調用模塊鉤子函數,對其節點的屬性進行替換,例如style,event等;再判斷節點子節點是否為文本節點,如果為文本節點則進行更替,如果還存在其他子節點則調用updateChildren,對子節點進行更新,更新流程將會回到第一步,重復;
這篇文章的重點就是說一下updateChildren這個函數
sameVnodefunction sameVnode(vnode1, vnode2) { return vnode1.key === vnode2.key && vnode1.sel === vnode2.sel; }
這是一個比較兩個vnode是否相似,是否值得去進行比較的函數,那么這里為什么會提到它?因為這里面有一個很重要的值---key
在平時的使用中幾乎用不到這個key值,不會去專門給它一個定義值,因為undefined===undefined,不會影響其比較;
key值的出現主要是為了應付一些場景
例如:
對于這種情況,如果按照正常的做法,就是一個個vnode去進行比較,發現其文本節點不對,就會一個個進行替換例如:
對于這種情況是否可以優化呢?
答案是可以的,我們可以刪除
那這里就涉及到一個標記值,標記著在新vnode中還有哪些舊的vnode存在,key值就是充當著這個角色。
[1(key:a),2(key:b),3(key:c)]
[2(key:b),3(key:c),4(key:d)]
[a,b,c] -> [a(x),b,c,d(+)] === [1,2,3] --> [1(x),2,3,4(+)]
key值與vnode形成了一個映射,可以看到,我們通過對key值的排序、增刪間接完成了對vnode的操作,使用最少的dom操作來完成了
如何對key值進行排序,增刪那這里就會有一個問題,我們如何完成上面的操作呢?這個過程我們可以理解為一種優化對比渲染的過程,也就是diff算法的核心
建議大家先看一下這一篇文章,圖文并茂
我這邊舉一個復雜的例子,記錄每一步的操作:
下面是頁面真實的dom,分別保存在自己vnode的elm屬性上;舊-->新
假設每個元素都有一個key值一一對應,且不重復,它們的key值分別為
a:1 a:1 b:2 d:6 c:3 f:4 f:4 --> h:8 e:5 k:9 d:6 b:2 g:7 g:7
將舊新vnode分別放入兩個數組
old:[vnode,....] new:[vnode,....]
其實我們是比較其key值是否相等,然后再決定如何排序,增刪vnode的位置,patch vnode,最終達到改變dom的目的,為了方便理解,我這里把其key值拿出來放入一個數組,每一個key在數組中的索引都對應著相應的vnode在其數組中的索引,在真實代碼中是直接比較vnode.key值。
oldKey:[1,2,3,4,5,6,7] oldStartIdx:0 oldStartVal:1 oldEndIdx:6 oldEndVal:7 newKey:[1,6,4,8,9,2,7] newStartIdx:0 newStartVal:1 newEndIdx:6 newEndVal:7
用的是雙指針的方法,頭尾同時開始掃描;
循環兩個數組,循環條件為(old_startIndex <= old_endIndex && new_startIndex <= new_endIndex)
(下面說的patch是直接對vnoe.elm進行修改,調用前面的patchVnode函數,也就是直接對頁面的dom進行修改,及時比較及時修改)
比較oldStartVal和newStartVal是否相等,如果相等則oldStartIdx和newStartIdx分別加1,并對oldStartVal對應的vnode進行patch,進入下一次循環;這個例子中oldStartVal==newStartVal,所以oldStartIdx:1 newStartIdx:1;若不相等,繼續比較;
比較過后: oldStartIdx:1 oldEndIdx:6 oldStartVal:2 oldEndVal:7 newStartIdx:1 newEndIdx:6 newStartVal:6 newEndVal:7 比較范圍縮小后: oldKey:[2,3,4,5,6,7] newKey:[6,4,8,9,2,7] dom:
比較oldEndVal和newEndVal是否相等,如果相等則oldEndIdx和newEndIdx分別減1,并對oldEndVal對應的舊vnode進行patch,進入下一次循環;這里oldEndVal==newEndVal,所以oldEndIdx:5 newEndIdx:5;若不相等,繼續比較;
比較過后: oldStartIdx:1 oldEndIdx:5 oldStartVal:2 oldEndVal:6 newStartIdx:1 newEndIdx:5 newStartVal:6 newEndVal:2 比較范圍縮小后: oldKey:[2,3,4,5,6] newKey:[6,4,8,9,2] dom:
比較oldStartVal和newEndVal是否相等,如果相等則oldStartIdx和newEndIdx分別加1和減1,oldStartVal對應的vnode移動到oldEndVal對應的vnode后面,并對移動的vnode進行patch,進入下一次循環;這里oldStartVal==newEndVal,所以oldStartIdx:2 newEndIdx:4;若不相等,繼續比較;
比較過后: oldStartIdx:2 oldEndIdx:5 oldStartVal:3 oldEndVal:6 newStartIdx:1 newEndIdx:4 newStartVal:6 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5,6] newKey:[6,4,8,9] dom:
比較oldEndVal和newStartVal是否相等,如果相等則oldEndIdx和newStartIdx分別減1和加1,oldEndVal對應的vnode移動到oldStart對應的vnode前面,并對移動的vnode進行patch,進入下一次循環;這里oldEndVal==newStartVal,所以oldEndIdx:4 newStartIdx:2;若不相等,繼續比較;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:2 newEndIdx:4 newStartVal:4 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[4,8,9] dom:
若不滿足上述判斷條件,查找newStartVal對應的vnode是否存在于舊vnode數組中。若存在,移動這個舊的vnode到oldStartVal對應的vnode前面,并對這個移動的vnode進行patch,在舊的vnode數組中將其原來的位置置為undefined,并且newStartIdx加1;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:3 newEndIdx:4 newStartVal:8 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[8,9] dom:
若不存在,則將這個newStartVal對應的vnde添加到oldStartVal對應的vnode前面,并且newStartIdx加1;
比較過后: oldStartIdx:2 oldEndIdx:4 oldStartVal:3 oldEndVal:5 newStartIdx:4 newEndIdx:4 newStartVal:9 newEndVal:9 比較范圍縮小后: oldKey:[3,4,5] newKey:[9] dom:
循環結束,判斷新舊vnode的key值哪個遍歷完,如果舊的便利完,若舊vnode數組遍歷完,則將剩余的新vnode數組中的vnode進行添加;若新vnode數組遍歷完,則刪除剩余的舊vnode數組中的vnode
在上面例子中,我們需要刪除oldVnodeArray中的三個vnode,索引分別為3,4,5,從而刪除了vnode對應的elm
最后得到最終的dom結構
上面的例子沒有將所有情況全部歸納進來,不過應該包含了大部分情況了。還需要注意的就是:
上面只是提到了key值,其實比較兩個vnode是否相似還有一個sel屬性,必須要兩個都相等才行
正常情況下key值用到的地方也是ul-li tr-td這種子元素重復的場景,因為這種情況下才會涉及到子元素順序改變還能復用
通過上面的分析,其實還可以發現一個key值的特點,就是唯一性和一一對應性。唯一性好理解,畢竟key值就是用來每個vnode自己的標示;一一對應代表著是你舊vnode和新vnode中如果沒有改變,則其key值應保持不變,之所以要提這個是因為很多地方看到了進行循環渲染的時候其key值都是用的數組的index進行賦值
如果考慮這種情況
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/100371.html
摘要:毫無疑問的是算法的復雜度與效率是決定能夠帶來性能提升效果的關鍵因素。速度略有損失,但可讀性大大提高。因此目前的主流算法趨向一致,在主要思路上,與的方式基本相同。在里面實現了的算法與支持。是唯一添加的方法所以只發生在中。 VirtualDOM是react在組件化開發場景下,針對DOM重排重繪性能瓶頸作出的重要優化方案,而他最具價值的核心功能是如何識別并保存新舊節點數據結構之間差異的方法,...
摘要:閑聊在學的過程中,虛擬應該是聽的最多的概念之一,得知其是借鑒進行開發,故習之。以我的觀點來看,多個相同元素渲染時,則需要為每個元素添加值。 閑聊:在學vue的過程中,虛擬dom應該是聽的最多的概念之一,得知其是借鑒snabbdom.js進行開發,故習之。由于我工作處于IE8的環境,對ES6,TS這些知識的練習也只是淺嘗輒止,而snabbdom.js從v.0.5.4這個版本后開始使用TS...
摘要:這個大概是的鉤子吧在每一次插入操作的時候都將節點這類型方法可以看出來是在調用對應的方法因為開始的時候就導入進來了插入節點操作的時候都需要加入子節點有子元素也就是的時候遞歸調用循環子節點生成對應著一些操作之后都要觸發鉤子函數。 snabbdom 本文的snabbdom源碼分析采用的是0.54版本(即未用ts重寫前的最后一版) 前期了解 snabbdom被用作vue的虛擬dom。本文的一個...
摘要:總共寫了四篇文章都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新介紹一下基本用法介紹一下渲染原理介紹一下的算法和對值的認識介紹一下對于兼容的修改這篇主要是記錄一下針對做了哪些修改增加用來兼容某些功能函數,例如等將每個文件單 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdo...
摘要:如果新舊的和都相同,說明兩個相似,我們就可以保留舊的節點,再具體去比較其差異性,在舊的上進行打補丁否則直接替換節點。 總共寫了四篇文章(都是自己的一些拙見,僅供參考,請多多指教,我這邊也會持續修正加更新) 介紹一下snabbdom基本用法 介紹一下snabbdom渲染原理 介紹一下snabddom的diff算法和對key值的認識 介紹一下對于兼容IE8的修改 這篇我將以自己的思路去...
閱讀 2122·2021-11-22 15:24
閱讀 2410·2021-09-09 11:53
閱讀 3037·2021-09-04 16:40
閱讀 1636·2019-08-30 15:52
閱讀 3355·2019-08-29 13:47
閱讀 2735·2019-08-26 17:40
閱讀 1541·2019-08-26 13:24
閱讀 2245·2019-08-26 12:01