當前位置:吉日网官网 - 傳統美德 - 40行代碼實現React core Diff算法

40行代碼實現React core Diff算法

如何設計Diff算法?考慮到只有以上三種情況,壹種常見的設計思路是:

按照這個方案,其實有壹個隱含的前提——不同操作的優先級是相同的。但是在日常開發中,節點移動發生的比較少,所以Diff算法會優先考慮其他情況。

基於這個概念,主流框架(React,Vue)的Diff算法都會經過多輪遍歷,先處理常見情況,再處理不常見情況。

因此,這就要求處理異常情況的算法需要能夠覆蓋各種邊界情況。

換句話說,僅通過使用處理異常情況的算法來完成Diff運算是完全可能的。主流框架出於性能原因不會這麽做。

本文將處理常見情況的算法砍掉,保留處理異常情況的算法。

這樣實現Diff的核心邏輯只需要40行代碼。

首先,我們定義虛擬DOM節點的數據結構:

Key是節點的唯壹標識符,用於關聯更改前後的節點。

Flag表示節點需要在Diff之後對相應的real DOM執行的操作,其中:

Index表示節點在同壹級別的索引位置。

註意:本演示只實現為壹個節點標誌,不根據標誌實現DOM操作。

我們想要實現的diff方法在更新前後接收節點列表,並用flag:

例如,對於:

{ key:“D”,flag:“Placement”}表示D對應DOM需要插入的頁面。

{ key:“A”,flag:“Deletion”}表示需要刪除A對應的DOM。

執行後的結果是:頁面中的A變成了d。

另壹個例子是:

因為B之前存在,{ key:“B”,flag:“Placement”}表示B對應的DOM需要後移(對應parentNode.appendChild的方法)。手術後Abc變成acb。

由於A之前存在,{ key:“A”,flag:“Placement”}表示A對應的DOM需要後移。這次手術後Acb變成了cba。

實現後的結果是頁面中的abc變成了cba。

核心邏輯包括三個步驟:

我們將每個節點保存在壹個映射中,用node.key作為鍵,node作為值。

這樣,在復雜度為O(1)的情況下,before中對應的節點可以通過key找到:

當遍歷after時,如果壹個節點同時存在於before和after中(鍵相同),我們稱之為可重用。

例如,在下面的例子中,b是可重用的:

對於可重用節點,這種更新必須屬於以下兩種情況之壹:

如何判斷可復用節點是否移動?

我們使用lastPlacedIndex變量來保存之前遍歷的最後壹個可重用節點的索引:

之後遍歷時,每輪遍歷的節點必須是當前遍歷的所有節點中最右邊的節點。

如果該節點是可重用節點,則nodeBefore和lastPlacedIndex之間有兩種關系:

註意:nodebefore表示before中可重用節點的對應節點。

這意味著在更新之前,該節點位於lastPlacedIndex的相應節點的左側。

更新後,該節點不在lastPlacedIndex對應的節點的左邊(因為它是當前遍歷的所有節點中最右邊的節點)。

這意味著節點已經向右移動,需要標記為放置。

節點已就位,不需要移動。

遍歷後,如果beforeMap中還有節點剩余,則意味著這些節點無法重用,需要標記並刪除。

例如,在遍歷after之後,beforeMap中還剩下{key: 'a'}:

這意味著需要標記和刪除A。

所以,最後,我們需要添加標簽刪除的邏輯:

  • 上一篇:太極傳24叫什麽?
  • 下一篇:低碳祭祀已經成為清明節的主流方式。如何看待這種發展趨勢?
  • copyright 2024吉日网官网