VorwortBei der Front-End-Entwicklung wird, solange Listen gerendert werden, unabhängig davon, ob es sich um ein React- oder Vue-Framework handelt, jedes Listenelement aufgefordert oder gefordert, einen eindeutigen Schlüssel zu verwenden. Viele Entwickler verwenden den Array-Index direkt als Schlüsselwert, ohne das Prinzip des Schlüssels zu kennen. In diesem Artikel wird die Rolle des Schlüssels erläutert und erklärt, warum es am besten ist, den Index nicht als Attributwert des Schlüssels zu verwenden. Die Rolle des SchlüsselsVue verwendet virtuelles DOM und vergleicht das alte und das neue DOM gemäß dem Diff-Algorithmus, um das reale DOM zu aktualisieren. Der Schlüssel ist die eindeutige Kennung des virtuellen DOM-Objekts. Der Schlüssel spielt im Diff-Algorithmus eine äußerst wichtige Rolle. Die Rolle des Schlüssels im Diff-AlgorithmusTatsächlich sind die Diff-Algorithmen in React und Vue ungefähr gleich, aber die Diff-Vergleichsmethoden sind immer noch ziemlich unterschiedlich und sogar die Diffs der einzelnen Versionen sind ziemlich unterschiedlich. Als nächstes nehmen wir den Vue3.0-Diff-Algorithmus als Ausgangspunkt, um die Rolle des Schlüssels im Diff-Algorithmus zu analysieren Der konkrete Diff-Prozess läuft wie folgt ab In Vue3.0 gibt es einen solchen Quellcode in der patchChildren-Methode wenn (PatchFlag > 0) { wenn (patchFlag & PatchFlags.KEYED_FRAGMENT) { /* Für den Fall, dass ein Schlüssel vorhanden ist, verwenden Sie den Diff-Algorithmus */ patchKeyedChildren( ... ) zurückkehren } sonst wenn (patchFlag & PatchFlags.UNKEYED_FRAGMENT) { /* Wenn der Schlüssel nicht existiert, patchen Sie ihn direkt */ patchUnkeyedChildren( ... ) zurückkehren } } patchChildren führt einen echten Diff oder einen direkten Patch aus, je nachdem, ob der Schlüssel vorhanden ist. Wir werden nicht auf den Fall eingehen, dass der Schlüssel nicht existiert. Sehen wir uns zunächst einige deklarierte Variablen an. /* c1 alter vnode c2 neuer vnode */ let i = 0 /* Datensatzindex */ const l2 = c2.length /* Anzahl neuer vnodes*/ let e1 = c1.length - 1 /* Index des letzten Knotens des alten vnode*/ let e2 = l2 - 1 /* Der Index des letzten Knotens des neuen Knotens*/ Kopfknoten synchronisierenDer erste Schritt besteht darin, denselben Vnode vom Anfang an zu finden und ihn dann zu patchen. Wenn es nicht derselbe Knoten ist, springen Sie sofort aus der Schleife heraus. //(ab) c //(ab) de /* Vergleichen Sie von Anfang an, um den gleichen Knoten-Patch zu finden. Wenn er unterschiedlich ist, springen Sie sofort heraus*/ während (i <= e1 und i <= e2) { Konstante n1 = c1[i] const n2 = (c2[i] = optimiert ? cloneIfMounted(c2[i] als VNode) : normalizeVNode(c2[i])) /*Überprüfen, ob Schlüssel und Typ gleich sind*/ wenn (isSameVNodeType(n1, n2)) { Patch ( ... ) } anders { brechen } ich++ } Der Ablauf ist wie folgt: isSameVNodeType wird verwendet, um zu bestimmen, ob der aktuelle Vnode-Typ dem Vnode-Schlüssel entspricht. Exportfunktion isSameVNodeType(n1: VNode, n2: VNode): boolean { gibt n1.Typ === n2.Typ und n1.Schlüssel === n2.Schlüssel zurück } Tatsächlich kennen wir dadurch bereits die Rolle des Schlüssels im Diff-Algorithmus, nämlich die Bestimmung, ob es sich um denselben Knoten handelt. Endknoten synchronisierenDer zweite Schritt beginnt am Ende mit dem gleichen Diff wie zuvor. //ein (bc) //de (bc) /* Wenn der erste Schritt nicht gepatcht ist, beginnen Sie sofort mit dem Patchen von hinten nach vorne. Wenn Sie Unterschiede feststellen, springen Sie sofort aus der Schleife heraus*/ während (i <= e1 und i <= e2) { Konstante n1 = c1[e1] const n2 = (c2[e2] = optimiert ? cloneIfMounted(c2[e2] als VNode) : normalizeVNode(c2[e2])) wenn (isSameVNodeType(n1, n2)) { Patch ( ... ) } anders { brechen } e1-- e2-- } Wenn nach dem ersten Schritt festgestellt wird, dass der Patch nicht vollständig ist, fahren Sie sofort mit dem zweiten Schritt fort. Beginnen Sie dabei am Ende und durchlaufen Sie den Vorwärts-Diff. Wenn es nicht derselbe Knoten ist, dann sofort aus der Schleife springen. Der Ablauf ist wie folgt: Einen neuen Knoten hinzufügenSchritt 3: Wenn alle alten Knoten gepatcht sind und die neuen Knoten nicht gepatcht sind, erstellen Sie einen neuen Vnode //(ab) //(ab) c //i = 2, e1 = 1, e2 = 2 //(ab) //c (ab) //i = 0, e1 = -1, e2 = 0 /* Wenn die Anzahl der neuen Knoten größer ist als die Anzahl der alten Knoten, werden alle verbleibenden Knoten als neue Vnodes verarbeitet (das bedeutet, dass derselbe Vnode gepatcht wurde) */ wenn (i > e1) { wenn (i <= e2) { const nextPos = e2 + 1 const anchor = nächstePos < l2 ? (c2[nextPos] als VNode).el : parentAnchor während (i <= e2) { patch (/* einen neuen Knoten erstellen */ ... ) ich++ } } } Der Ablauf ist wie folgt: Löschen redundanter KnotenSchritt 4: Wenn alle neuen Knoten gepatcht sind und noch einige alte Knoten übrig sind, deinstallieren Sie alle alten Knoten. //ich > e2 //(ab) c //(ab) //i = 2, e1 = 2, e2 = 1 //ein (bc) //(bc) //i = 0, e1 = 0, e2 = -1 sonst wenn (i > e2) { während (i <= e1) { aushängen(c1[i], übergeordnete Komponente, übergeordnete Spannung, wahr) ich++ } } Der Ablauf ist wie folgt: Längste zunehmende TeilfolgeZu diesem Zeitpunkt ist die Kernszene noch nicht erschienen. Wenn wir Glück haben, könnte es hier enden, aber wir können uns nicht ausschließlich auf Glück verlassen. Das verbleibende Szenario ist, dass sowohl der neue als auch der alte Knoten mehrere untergeordnete Knoten haben. Sehen wir uns als Nächstes an, wie Vue3 das macht. So kombinieren Sie Verschiebe-, Hinzufügungs- und Deinstallationsvorgänge Jedes Mal, wenn wir ein Element verschieben, können wir ein Muster erkennen. Wenn wir es so selten wie möglich verschieben möchten, bedeutet dies, dass einige Elemente stabil sein müssen. Was sind also die Muster für Elemente, die stabil bleiben können? Schauen Sie sich das obige Beispiel an: c h d e VS d e i c. Beim Vergleichen können Sie mit bloßem Auge erkennen, dass Sie c nur ans Ende verschieben, dann h deinstallieren und i hinzufügen müssen. d e kann unverändert bleiben. Es zeigt sich, dass die Reihenfolge von d e in den neuen und alten Knoten unverändert bleibt. d kommt nach e und der Index ist in einem zunehmenden Zustand.
Die nächste Idee ist: Wenn wir die Knoten finden, deren Reihenfolge in der neuen Knotensequenz unverändert bleibt, wissen wir, welche Knoten nicht verschoben werden müssen, und müssen dann nur die Knoten einfügen, die nicht hier sind. Denn die endgültige Reihenfolge, die dargestellt werden soll, ist die Reihenfolge der neuen Knoten, und die Bewegung ist lediglich die Bewegung der alten Knoten. Solange die alten Knoten also die längste Reihenfolge unverändert beibehalten, kann die Konsistenz damit durch Verschieben einzelner Knoten gewahrt werden. Suchen Sie also vorher zuerst alle Knoten und dann die entsprechende Sequenz. Was wir am Ende eigentlich erhalten wollen, ist dieses Array: [2, 3, neu, 0]. Tatsächlich ist dies die Idee der Diff-Bewegung Warum keinen Index verwenden?LeistungskostenBei Verwendung eines Index als Schlüssel wird der sequentielle Vorgang zerstört, da nicht jeder Knoten den entsprechenden Schlüssel finden kann, einige Knoten nicht wiederverwendet werden können und alle neuen Vnodes neu erstellt werden müssen. Beispiel: <Vorlage> <div Klasse="hallo"> <ul> <li v-for="(item,index) in studentList" :key="index">{{item.name}}</li> <br> <button @click="addStudent">Datenelement hinzufügen</button> </ul> </div> </Vorlage> <Skript> Standard exportieren { Name: "Hallo Welt", Daten() { zurückkehren { Studentenliste: [ { ID: 1, Name: '张三', Alter: 18 }, { ID: 2, Name: 'Li Si', Alter: 19 }, ], }; }, Methoden:{ addStudent(){ const studentObj = { id: 3, name: 'student', age: 20 }; diese.studentenliste=[studentenobj,...diese.studentenliste] } } } </Skript> Öffnen wir zuerst den Chrome-Debugger und doppelklicken Sie dann, um den darin enthaltenen Text zu ändern. Lassen Sie uns den obigen Code ausführen und die Ergebnisse ansehen. Aus den obigen Ergebnissen können wir ersehen, dass wir nur ein Datenelement hinzugefügt haben, aber alle drei Datenelemente neu gerendert werden müssen. Ist das nicht überraschend? Ich habe offensichtlich nur ein Datenelement eingefügt, warum müssen alle drei Datenelemente neu gerendert werden? Und ich möchte lediglich die neu hinzugefügten Daten rendern. Wir haben oben auch über die Diff-Vergleichsmethode gesprochen. Lassen Sie uns nun ein Bild basierend auf dem Diff-Vergleich zeichnen, um zu sehen, wie der Vergleich durchgeführt wird. Wenn wir vorne ein Datenelement hinzufügen, wird die Indexreihenfolge unterbrochen, wodurch sich alle Schlüssel der neuen Knoten ändern und die Daten auf unserer Seite neu gerendert werden. Als nächstes generieren wir 1000 DOMs, um die Leistung bei Verwendung eines Index und bei Nichtverwendung eines Index zu vergleichen. Um die Eindeutigkeit des Schlüssels sicherzustellen, verwenden wir UUID als Schlüssel. Verwenden wir den Index als Schlüssel und führen ihn einmal aus <Vorlage> <div Klasse="hallo"> <ul> <button @click="addStudent">Datenelement hinzufügen</button> <br> <li v-for="(item,index) in studentList" :key="index">{{item.id}}</li> </ul> </div> </Vorlage> <Skript> importiere uuidv1 von „uuid/v1“ Standard exportieren { Name: "Hallo Welt", Daten() { zurückkehren { Studentenliste: [{id:uuidv1()}], }; }, erstellt(){ für (sei i = 0; i < 1000; i++) { diese.studentList.push({ Ich würde sagen: uuidv1(), }); } }, vorUpdate(){ Konsole.Zeit('für'); }, aktualisiert(){ console.timeEnd('für') //für: 75,259033203125 ms }, Methoden:{ addStudent(){ const studentObj = { id: uuidv1() }; diese.studentenliste=[studentenobj,...diese.studentenliste] } } } </Skript> Ersetzen Sie die ID durch den Schlüssel <Vorlage> <div Klasse="hallo"> <ul> <button @click="addStudent">Datenelement hinzufügen</button> <br> <li v-for="(item,index) in studentList" :key="item.id">{{item.id}}</li> </ul> </div> </Vorlage> vorUpdate(){ Konsole.Zeit('für'); }, aktualisiert(){ console.timeEnd('für') //für: 42,200927734375 ms }, Aus dem obigen Vergleich können wir erkennen, dass die Verwendung eines eindeutigen Wertes als Schlüssel Mehraufwand sparen kann DatenfehlausrichtungIm obigen Beispiel denken Sie vielleicht, dass die Verwendung des Index als Schlüssel nur die Effizienz des Seitenladens beeinflusst, und dass eine kleine Datenmenge kaum Auswirkungen hat. Im folgenden Fall kann die Verwendung des Index einige unerwartete Probleme verursachen. Im obigen Szenario füge ich immer noch zuerst nach jedem Textinhalt ein Eingabefeld hinzu, fülle manuell etwas Inhalt in das Eingabefeld aus und verwende dann die Schaltfläche, um einen Klassenkameraden weiterzuhängen. <Vorlage> <div Klasse="hallo"> <ul> <li v-for="(item,index) in studentList" :key="index">{{item.name}}<input /></li> <br> <button @click="addStudent">Datenelement hinzufügen</button> </ul> </div> </Vorlage> <Skript> Standard exportieren { Name: "Hallo Welt", Daten() { zurückkehren { Studentenliste: [ { ID: 1, Name: '张三', Alter: 18 }, { ID: 2, Name: 'Li Si', Alter: 19 }, ], }; }, Methoden:{ addStudent(){ const studentObj = { id: 3, name: 'student', age: 20 }; diese.studentenliste=[studentenobj,...diese.studentenliste] } } } </Skript> Geben wir einige Werte in die Eingabe ein und fügen einen Klassenkameraden hinzu, um den Effekt zu sehen: Zu diesem Zeitpunkt stellen wir fest, dass die vor dem Hinzufügen eingegebenen Daten falsch platziert sind. Nach dem Hinzufügen verbleiben die Informationen von Zhang San im Eingabefeld von Wang Wu, was offensichtlich nicht das gewünschte Ergebnis ist. Aus dem obigen Vergleich können wir ersehen, dass beim Vergleichen festgestellt wird, dass sich der Textwert zwar geändert hat, da der Index als Schlüssel verwendet wird. Beim weiteren Abwärtsvergleich stellt sich jedoch heraus, dass der Eingabe-DOM-Knoten immer noch derselbe ist wie zuvor und daher wiederverwendet wird. Es ist jedoch unerwartet, dass das Eingabefeld den Eingabewert beibehält, und zu diesem Zeitpunkt wird der Eingabewert falsch platziert. LösungDa wir wissen, dass die Verwendung eines Index in einigen Fällen sehr negative Auswirkungen haben kann, stellt sich die Frage, wie wir dieses Problem während der Entwicklung lösen können. Tatsächlich werden die folgenden drei Situationen bei der Entwicklung im Allgemeinen häufiger verwendet, solange der Schlüssel eindeutig und unverändert ist.
lass a=Symbol('test') lass b = Symbol('Test') console.log(a===b) //false Als Schlüssel können Sie uuid verwenden. uuid ist die Abkürzung für Universally Unique Identifier. Es handelt sich dabei um eine maschinengenerierte Kennung, die innerhalb eines bestimmten Bereichs (von einem bestimmten Namensraum bis hin zur ganzen Welt) eindeutig ist. Wir verwenden die erste Lösung oben als Schlüssel und betrachten die obige Situation noch einmal, wie in der Abbildung dargestellt. Knoten mit demselben Schlüssel werden wiederverwendet. Dies ist die eigentliche Wirkung des Diff-Algorithmus. Zusammenfassen
Damit ist dieser Artikel darüber, warum es nicht empfohlen wird, in Vue einen Index als Schlüssel zu verwenden, abgeschlossen. Weitere relevante Inhalte zum Vue-Index als Schlüssel finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
<<: Designtheorie: Menschenorientiertes Designkonzept
>>: CSS-Leistungsoptimierung - detaillierte Erklärung der Will-Change-Verwendung
In der Welt der Webentwicklung sind Frameworks wei...
In diesem Artikel werden die spezifischen Schritt...
Verwenden Sie Nginx, um einen Tomcat9-Cluster zu ...
1. Gründe Wenn das System Centos7.3 ist, ist die ...
Binäre MySQL-Installationsmethode Laden Sie mysql...
INSERT INTO hk_test(Benutzername, Passwort) VALUE...
Inhaltsverzeichnis 1. Was ist SVN? 2. Methoden zu...
Inhaltsverzeichnis 1. v-wenn 2. Verwenden Sie v-i...
einführen HTML stellt die kontextuelle Struktur u...
Werfen wir zunächst einen Blick auf die allgemein...
Dieser Artikel beschreibt, wie man OpenCV mit C++...
Inhaltsverzeichnis 1. Optionaler Verkettungsopera...
Warum kann es die Höhe festlegen, aber im Gegensat...
1. Der Unterschied zwischen HTTP und HTTPS HTTP: ...
Inhaltsverzeichnis MySQL-Berechtigungskontrolle B...