為了增強用戶體驗,React從16版本開始將同步更新重構為可中斷的異步更新,即采用了新的協調器(coordinator for find the changed components),新的協調器采用了纖程架構。這裏不詳細解釋光纖架構的原理。目前我們只需要知道纖程節點可以存儲dom信息,纖程節點形成的樹稱為纖程樹。更新dom需要‘雙緩存技術’,也就是將舊的纖維樹與這次要渲染的jsx對象進行比較,然後返回到新的纖維樹進行渲染。當比較舊的纖程樹和jsx對象時,決定重用哪些節點的過程是diff算法。
由於diff本身也會帶來性能消耗,為了降低算法的復雜度,React對diff做了三個預設限制:
截至上次更新
如果沒有密鑰,將采取第二個限制。有了密鑰,react就可以判斷div和P節點存在並且可以重用,只需要交換順序即可。
Diff算法會根據不同的jsx對象執行不同的處理功能。根據不同的jsx對象,我們可以分為兩類:
1的類型。JSX對象(所有這些後來都由newChildren表示)是對象、數字和字符串,這意味著在同壹級別上只有壹個節點。
2.NewChildren的類型是Array,這意味著在同壹級別上有多個節點。
第二,單節點差異
對於單節點diff,可以用流程圖來解釋。
截至上次更新
由於key的默認值為null,更新前後的key相同,元素類型不同,因此我們需要刪除更新前的三個div節點並添加P節點。
第三,多節點差異
對於多節點diff,我們需要遍歷newChildren和oldFiber進行比較。因為React團隊發現dom節點壹般有三個操作:更新、添加和刪除,而且更新更頻繁,所以他們將更新的優先級設置得比添加和刪除更高。由於上述原因,在多節點diff算法的實現中存在兩層遍歷。第壹層遍歷更新的節點,第二層遍歷更新以外的節點。
第壹級遍歷
遍歷newChildren和oldFiber以確定節點是否可以重用,如果可以重用,則繼續遍歷。
如果不能重復使用,可以分為兩種情況:
二級遍歷
第二級遍歷從第壹級遍歷的結束位開始。
第壹層遍歷後有四種結果。
首先,我們需要判斷newChildren中遍歷的節點是否存在於oldFiber中。基於此,React將oldFiber中的節點以key-oldfiber鍵值對的形式存儲在Map中,我們只需要newChildren的key就可以判斷oldfiber中是否有對應的節點。
如果oldfiber中沒有相應的節點,則newChildren生成的纖程將被標記為放置。
如果有對應的節點,將其索引記錄為oldIndex,並與oldFiber中最後壹個可重用節點的索引位置lastPlacedIndex進行比較。如果可重用節點位於最後壹個可重用節點的右側,這意味著位置沒有改變,即
如果old index》= lastPlacedIndex,表示相對位置沒有改變,則讓lastPlacedIndex=oldIndex。
If oldindex
例如:
參考文件:
React技術的秘密(iamkasong.com)