Jsx 表面寫的是html,其實內部執行的是一段js
createElementhtml
React.createElement( type, [props], [...children] )
createElement把這個樹形結構,存在內存裏面
Jsx最終以這樣的一個個對象遞歸的存在內存中,執行diff算法
多層結構
react
簡單的createElement實現算法
reactElement - 生成的是一個對象來描述這個節點dom
與傳統樹的diff的區別性能
計算一棵樹形結構轉換成另外一棵樹形結構的最少操做,是一個複雜且值得研究的問題。傳統 diff 算法經過循環遞歸對節點進行依次對比,效率低下,算法複雜度達到 O(n^3)優化
react diff策略spa
tree diffcode
基於策略一,對樹進行分層比較,兩棵樹只會對同一層次的節點進行比較。 React 經過 updateDepth 對 Virtual DOM 樹進行層級控制,同一個父節點下的全部子節點。
什麼是 DOM 節點跨層級的移動操做?component
A 節點(包括其子節點)整個被移動到 D 節點下
若是出現了 DOM 節點跨層級的移動操做,React diff 會有怎樣的表現呢?htm
React 只會簡單的考慮同層級節點的位置變換,而對於不一樣層級的節點,只有建立和刪除操做。
當根節點發現子節點中 A 消失了,就會直接銷燬 A;當 D 發現多了一個子節點 A,則會建立新的 A(包括子節點)做爲其子節點。此時,React diff 的執行狀況:create A -> create B -> create C -> delete A。
注意:
在開發組件時,保持穩定的 DOM 結構會有助於性能的提高。例如,能夠經過 CSS 隱藏或顯示節點,而不是真的移除或添加 DOM 節點。
component diff
依據策略二
React 判斷 D 和 G 是不一樣類型的組件,就不會比較兩者的結構,而是直接刪除 component D,從新建立 component G 以及其子節點,即便D 和 G的結構很類似
element diff
當節點處於同一層級時,React diff 提供了三種節點操做,分別爲:INSERT_MARKUP(插入)、MOVE_EXISTING(移動)和 REMOVE_NODE(刪除)。
eg: 新老集合進行 diff 差別化對比,發現 B != A,則建立並插入 B 至新集合,刪除老集合 A;以此類推,建立並插入 A、D 和 C,刪除 B、C 和 D。
帶來的問題:都是相同的節點,但因爲位置發生變化,致使須要進行繁雜低效的刪除、建立操做,其實只要對這些節點進行位置移動便可
react優化策略:容許開發者對同一層級的同組子節點,添加惟一 key 進行區分
優化後diff實現:
分析:
element _mountIndex lastIndex nextIndex enqueueMove B 1 0 0 false A 0 1 1 true D 3 1 2 false C 2 3 3 true
step:
重新集合中取得 B,判斷老集合中存在相同節點 B B 在老集合中的位置 B._mountIndex = 1 初始 lastIndex = 0 不知足 child._mountIndex < lastIndex 的條件,所以不對 B 進行移動操做 更新 lastIndex = Math.max(prevChild._mountIndex, lastIndex) lastIndex更新爲1 將 B 的位置更新爲新集合中的位置prevChild._mountIndex = nextIndex,此時新集合中 B._mountIndex = 0,nextIndex++
以上主要分析新老集合中存在相同節點但位置不一樣時,對節點進行位置移動的狀況,若是新集合中有新加入的節點且老集合存在須要刪除的節點,那麼 React diff 又是如何對比運做的呢?
element _mountIndex lastIndex nextIndex enqueueMove B 1 0 0 false E no exist C 2 1 2 false A 0 2 3 true
step
新建:重新集合中取得 E,判斷老集合中不存在相同節點 E,則建立新節點 E lastIndex不作處理 E 的位置更新爲新集合中的位置,nextIndex++ 刪除:當完成新集合中全部節點 diff 時,最後還須要對老集合進行循環遍歷,判斷是否存在新集合中沒有但老集合中仍存在的節點,發現存在這樣的節點 D,所以刪除節點 D
react diff的問題
理論上 diff 應該只需對 D 執行移動操做,然而因爲 D 在老集合的位置是最大的,致使其餘節點的 _mountIndex < lastIndex,形成 D 沒有執行移動操做,而是 A、B、C 所有移動到 D 節點後面的現象
建議:在開發過程當中,儘可能減小相似將最後一個節點移動到列表首部的操做,當節點數量過大或更新操做過於頻繁時,在必定程度上會影響 React 的渲染性能。
總結:
https://zhuanlan.zhihu.com/p/...