Heim > Artikel > Web-Frontend > Erklärung des virtuellen Dom- und Diff-Algorithmus in React (mit Code)
Der Inhalt dieses Artikels befasst sich mit der Erklärung des virtuellen Dom- und Diff-Algorithmus in React (mit Code). Ich hoffe, dass er hilfreich ist Du hast geholfen.
Virtual dom
Jsx schreibt HTML auf der Oberfläche, führt aber tatsächlich einen Teil von js intern aus
createElement
React.createElement( type, [props], [...children] )
createElement speichert diese Baumstruktur im Speicher
Jsx speichert solche Objekte schließlich rekursiv im Speicher und führt den Diff-Algorithmus aus.
Mehrschichtiger Aufbau
Einfach createElement implementiert
reactElement – was generiert wird, ist ein Objekt zur Beschreibung dieses Knotens
React Diff
Der Unterschied zwischen React Diff und traditionellem Tree Diff
Die Berechnung der minimalen Operationen, die erforderlich sind, um eine Baumstruktur in eine andere Baumstruktur umzuwandeln, ist ein komplexes und forschungswürdiges Problem. Der herkömmliche Diff-Algorithmus vergleicht Knoten nacheinander durch Schleifenrekursion, was ineffizient ist und die Komplexität des Algorithmus O(n^3) erreicht
Diff-Strategie reagieren
Es gibt nur sehr wenige ebenenübergreifende Bewegungsvorgänge von DOM-Knoten in der Web-Benutzeroberfläche und können ignoriert werden.
Zwei Komponenten mit derselben Klasse erzeugen ähnliche Baumstrukturen, und zwei Komponenten mit unterschiedlichen Klassen erzeugen unterschiedliche Baumstrukturen.
Eine Gruppe untergeordneter Knoten auf derselben Ebene kann durch eine eindeutige ID unterschieden werden.
Baumunterschied
Basierend auf Strategie eins werden Bäume hierarchisch verglichen.
React verwendet updateDepth, um eine hierarchische Steuerung des virtuellen DOM-Baums durchzuführen, wobei sich alle untergeordneten Knoten unter demselben übergeordneten Knoten befinden.
Was ist die ebenenübergreifende Bewegungsoperation von DOM-Knoten?
Der gesamte A-Knoten (einschließlich seiner untergeordneten Knoten) wird auf den D-Knoten verschoben
Wenn es sich um einen DOM-Knoten handelt erscheint. Wie verhält sich React Diff bei verschieben-Ebenen-übergreifenden Vorgängen?
React berücksichtigt lediglich die Positionsänderungen von Knoten auf derselben Ebene, während es für Knoten auf verschiedenen Ebenen nur Erstellungs- und Löschvorgänge gibt.
Wenn der Wurzelknoten feststellt, dass A im untergeordneten Knoten verschwunden ist, wird A direkt zerstört. Wenn D feststellt, dass es einen zusätzlichen untergeordneten Knoten A gibt, wird ein neues A (einschließlich untergeordneter Knoten) erstellt Knoten) als untergeordneten Knoten. Zu diesem Zeitpunkt erfolgt die Ausführung von React Diff: create A -> create B ->
Hinweis:
Bei der Entwicklung von Komponenten hilft die Aufrechterhaltung einer stabilen DOM-Struktur, die Leistung zu verbessern. Sie können beispielsweise Knoten über CSS ein- oder ausblenden, ohne tatsächlich DOM-Knoten entfernen oder hinzufügen zu müssen.
Komponentenunterschied
Basierend auf Strategie zwei
Wenn es sich um Komponenten desselben Typs handelt, fahren Sie fort mit Vergleichen Sie den virtuellen DOM-Baum gemäß der ursprünglichen Strategie.
Wenn nicht, wird die Komponente als schmutzige Komponente beurteilt, wodurch alle untergeordneten Knoten unter der gesamten Komponente ersetzt werden.
Für den gleichen Komponententyp gibt es möglicherweise keine Änderungen in seinem virtuellen DOM. Wenn Sie dies sicher wissen, können Sie viel Diff-Operationszeit sparen, so dass React dies zulässt Benutzer müssen ShouldComponentUpdate( ) übergeben, um zu bestimmen, ob für die Komponente ein Unterschied gemacht werden muss.
React stellt fest, dass D und G unterschiedliche Arten von Komponenten sind, daher vergleicht es nicht die Strukturen der beiden, sondern löscht Komponente D direkt und erstellt Komponente G und ihre untergeordneten Knoten neu , auch wenn D der Struktur von G sehr ähnlich ist auf der gleichen Ebene, React diff Es werden drei Knotenoperationen bereitgestellt: INSERT_MARKUP (Einfügung), MOVE_EXISTING (Verschiebung) und REMOVE_NODE (Löschung).
INSERT_MARKUP,新的 component 类型不在老集合里, 即是全新的节点,需要对新节点执行插入操作。
MOVE_EXISTING,在老集合有新 component 类型,且 element 是可更新的类型,generateComponentChildren 已调用 receiveComponent,这种情况下 prevChild=nextChild,就需要做移动操作,可以复用以前的 DOM 节点。
REMOVE_NODE,老 component 类型,在新集合里也有,但对应的 element 不同则不能直接复用和更新,需要执行删除操作,或者老 component 不在新集合里的,也需要执行删除操作。
eg: 新老集合进行 diff 差异化对比,发现 B != A,则创建并插入 B 至新集合,删除老集合 A;以此类推,创建并插入 A、D 和 C,删除 B、C 和 D。
带来的问题:都是相同的节点,但由于位置发生变化,导致需要进行繁杂低效的删除、创建操作,其实只要对这些节点进行位置移动即可
react优化策略:允许开发者对同一层级的同组子节点,添加唯一 key 进行区分
优化后diff实现:
对新集合的节点进行循环遍历,通过唯一 key 可以判断新老集合中是否存在相同的节点
如果存在相同节点,则进行移动操作,但在移动前需要将当前节点在老集合中的位置child._mountIndex与lastIndex(访问过的节点在老集合中最右的位置即最大的位置)进行比较,if (child._mountIndex
分析:
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 = 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,则创建新节点 Ereact diff的问题
理论上 diff 应该只需对 D 执行移动操作,然而由于 D 在老集合的位置是最大的,导致其他节点的 _mountIndex
建议:在开发过程中,尽量减少类似将最后一个节点移动到列表首部的操作,当节点数量过大或更新操作过于频繁时,在一定程度上会影响 React 的渲染性能。
总结:
React 通过制定大胆的 diff 策略,将 O(n3) 复杂度的问题转换成 O(n) 复杂度的问题;
React 通过分层求异的策略,对 tree diff 进行算法优化;
React 通过相同类生成相似树形结构,不同类生成不同树形结构的策略,对 component diff 进行算法优化;
React 通过设置唯一 key的策略,对 element diff 进行算法优化;
建议,在开发组件时,保持稳定的 DOM 结构会有助于性能的提升;
Es wird empfohlen, während des Entwicklungsprozesses Vorgänge wie das Verschieben des letzten Knotens an den Anfang der Liste zu minimieren, wenn die Anzahl der Knoten zu groß ist oder Aktualisierungsvorgänge zu häufig sind. Dies wirkt sich bis zu einem gewissen Grad auf die Rendering-Leistung aus.
Das obige ist der detaillierte Inhalt vonErklärung des virtuellen Dom- und Diff-Algorithmus in React (mit Code). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!