Virtual DOM diff算法原理
以前在解決一次flatlist沒有局部刷新的問題時寫了一篇博客里面提到了官方的一篇文檔叫做reconciliation。前陣子有人問我react的virtualDomTree的diff算法是怎么實現的有沒做什么優化點。我知道是這篇文章里的內容但當時卻說不清楚這讓我覺得我對這篇文章其實理解的并不夠所以把它再看一遍然后把自己的理解記錄下來但這并不是翻譯完全是按照我自己的理解來寫的并不會非常嚴謹但應該不會有誤如果有不同看法歡迎討論。
正常來說Dom樹的diff算法復雜度是O(n^3)如果頁面很復雜時性能就非常低了比如有1000個節點的樹需要比較一億次。React進行優化后實際的復雜度降低到了O(n)它基于兩個原則
兩個節點類型不同的話以其為根節點的樹也完全不同
通過節點的key屬性可以定位新舊Dom樹上對應的節點來判定是否需要rerender
首先看如何比較假定我們已經確定了要比較的節點
如果節點類型不同比如原來是Image現在是View。那么以這個節點為根節點的整個Dom樹都需要新建。它本身的屬性以及所有的子節點都沒有比較的必要了。
如果節點類型相同那么就比較它的屬性只有那些發生了變化的屬性會被記錄下來然后進行更新沒有發生變化的屬性也就保持不變。然后循環遍歷它的所有子孫節點進行比較。
需要注意一下一旦一個節點比較有了diff也就是變得dirty那么它本身以及所有的子孫節點都會變成dirty。diff會生成但是否觸發re-render取決于具體實現。不要誤認為只要有diff必然會導致re-render或者只要沒觸發re-render就沒有diff。
然后就是我們怎么確定某個節點在新舊Dom樹上如何對應的假設下面這種場景
//old????1????2//new1????1????2????3//new2????3????1????2
old指老的Dom樹new1在它的末尾插入了一個新的子節點根據上面的原則根節點View和Text1,Text2都沒有變化只是新增了Text3而已。但new2就不一樣了它在起始插入了一個Text3這就導致Text1變成了Text3Text2變成了Text1然后新加了一個Text2這顯然是不太合適的明明只增加了一個子節點但三個都重繪了。例子中Text是一個很簡單的組件實際上它可以是一個非常復雜的根節點那樣的話可能就導致一整個Dom樹的變動了。
解決這個問題的方案就是給Component添加了key屬性。一個節點的所有子節點擁有一個唯一的key注意這個唯一并不是全局的唯一只需要跟它的兄弟節點區分開來就行。加上key之后再看上面的例子
//old????1?????2//new2????3?????1?????2
現在在進行diff時就知道了key為1和2的Text節點內容沒有變化不會生成diff只需要增加Text3就可以了。
文檔里提到在項目開發中key的設置不要太過隨意例如直接使用index如果這樣當子控件順序發生變化時可能就產生了額外的diff。我在使用flatlist時keyExtractor直接使用index導致在數組起始插入一個數據時整個flatlist全部進行了刷新而不是局部刷新就是這個原因。
最后有兩個結論
如果沒有必要不要輕易改變一個節點的類型。也就是說顯示效果沒變卻改變節點類型。這在實際情況中很少發生。
使用一個穩定和唯一的key來讓組件和它的兄弟組件區分不使用或者不合理的使用可能造成性能問題。
本文轉載自異步社區
Web應用防火墻 WAF
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。