Eine Untersuchung des JS-Operators im Problem

Eine Untersuchung des JS-Operators im Problem

Die Sache ist: Jeder kennt „Speicherlecks“. Es gibt mehrere gängige Szenarien:

  • Unsachgemäßer Einsatz von Closures führt zu Speicherlecks
  • (Nicht deklarierte) globale Variablen
  • Getrennte DOM-Knoten
  • (Optional) Drucken auf der Konsole
  • Vergessener Timer
  • Zirkuläre Referenzen

Speicherlecks müssen ernst genommen werden. Sie sind so schwerwiegend, dass sie sogar zum Einfrieren von Seiten führen und das Benutzererlebnis beeinträchtigen können!

Punkt 3 hat meine Aufmerksamkeit erregt. Ich weiß genau, was er bedeutet, zum Beispiel: „Angenommen, Sie entfernen manuell einen DOM-Knoten und der vom DOM-Knoten belegte Speicher sollte freigegeben werden, aber aufgrund von Nachlässigkeit enthält ein Teil des Codes immer noch einen Verweis auf den entfernten Knoten, was letztendlich dazu führt, dass der vom Knoten belegte Speicher nicht freigegeben wird.“

<div id="Wurzel">
    <div class="child">Ich bin ein untergeordnetes Element</div>
    <button>Entfernen</button>
</div>
<Skript>
    let btn = document.querySelector('Schaltfläche')
    let Kind = Dokument.QuerySelector('.Kind')
    let root = document.querySelector('#root')
    
    btn.addEventListener('klicken', function() {
        root.removeChild(Kind)
    })

</Skript>

Dieser Code entfernt den Knoten .child nach dem Klicken auf die Schaltfläche. Obwohl der Knoten nach dem Klicken tatsächlich aus dem DOM entfernt wird, weist die globale Variable child immer noch einen Verweis auf den Knoten auf, sodass der Speicher des Knotens nicht freigegeben werden kann.

Lösung : Wir können den Verweis auf den .child-Knoten in die Rückruffunktion des Klickereignisses verschieben. Wenn dann der Knoten entfernt und die Rückruffunktion beendet wird, wird der Verweis auf den Knoten automatisch gelöscht, und es tritt natürlich kein Speicherverlust auf. (Dies ist tatsächlich eine Echtzeiterkennung, ob der Knoten im Ereignis vorhanden ist. Wenn er nicht vorhanden ist, löst der Browser die Ausführung der Entfernungsfunktion nicht aus.)

<div id="Wurzel">
    <div class="child">Ich bin ein untergeordnetes Element</div>
    <button>Entfernen</button>
</div>
<Skript>
    let btn = document.querySelector('Schaltfläche')

    btn.addEventListener('klicken', function() {  
        let Kind = Dokument.QuerySelector('.Kind')
        let root = document.querySelector('#root')

        root.removeChild(Kind)
    })

</Skript>

Ist dieser Code perfekt? NEIN. Weil es nach dem Auslösen jedes Ereignisses Verweise auf die untergeordneten und Stammknoten erstellt. Speicherverbrauch (Sie können sich vorstellen, dass einige Leute verrückt werden

Tastenklicks…).

Tatsächlich geht es auch anders: Wir ermitteln per Klick, ob im aktuellen Root-Knoten noch ein Child-Knoten vorhanden ist. Wenn ja, führen wir die Remove-Funktion aus, andernfalls tun wir nichts!

Dies führt zu dem im Titel genannten Verhalten.

Wie soll man urteilen?

Traverse? Nein, das macht zu viel Mühe!

Irgendwie fiel mir plötzlich der In-Operator in for...in , der Objekte basierend auf der Prototypenkette durchlaufen kann!

Lassen Sie uns die Szene zu diesem Zeitpunkt wiederherstellen: Öffnen Sie GitHub, suchen Sie nach dem Zufallsprinzip einen übergeordneten Knoten und rufen Sie ihn ab:

meingithub

Der rote Rahmen im Bild ist das übergeordnete Element, das wir erhalten möchten, und der orangefarbene Rahmen ist das untergeordnete Element, bei dem wir feststellen möchten, ob es vorhanden ist.

let parent = document.querySelector('.position-relative');
let child = document.querySelector('.progress-pjax-loader');

Beachten Sie hier, dass wir einen DOM-Knoten (Array-ähnliches Objekt) erhalten und diesen vor der Operation verarbeiten müssen:

Objekt

let p_child=[...Eltern.Kinder];

Anordnung

Dann

Konsole.log(Kind in p_child);

nicht

! ! !

Warum? (Zu diesem Zeitpunkt war dem Autor der Ernst der Lage noch nicht bewusst)

Ich frage mich, ob etwas schiefgelaufen ist, also verwende ich zur Überprüfung die ES6-Includes-API:

Konsole.log(p_child.includes(Kind));

Ja

Das stimmt!

Lassen Sie es uns mit einem normalen Array überprüfen:

Überprüfung

? ? ?

An diesem Punkt fiel mir ein, MDN zu überprüfen:

mdn

Dann habe ich Folgendes festgestellt: Wenn der In-Operator allein verwendet wird, erkennt er, ob der Wert, der dem Wert auf der linken Seite (als Index) entspricht, innerhalb des Objekts auf der rechten Seite (in den Eigenschaften und dem Prototyp) liegt !

Zurück zum obigen Code. Wir stellen Folgendes fest:

verifizierung_2

Dies bestätigt unsere Schlussfolgerung.

Offensichtlich ist „untergeordnetes Element“ nicht dasselbe wie „in der Prototypenkette vorhanden“ – dies führt zu einem weiteren Wissenspunkt: dem Unterschied zwischen Attribut und Eigenschaft!

Nach einigen „Problemen“ sollte der Quellcode also direkt so lauten:

<div id="Wurzel">
    <div class="child">Ich bin ein untergeordnetes Element</div>
    <button>Entfernen</button>
</div>
<Skript>
    let btn = document.querySelector('Schaltfläche')
    let Kind = Dokument.QuerySelector('.Kind')
    let root = document.querySelector('#root')
    lass r_child = [...root.children]
    
    btn.addEventListener('klicken', function() {
        if(r_child.includes(child)){ // Oder Sie können einfach prüfen, ob das Kind null ist... root.removeChild(child)
        }
    })

</Skript>

Ein etwas voreiliges Ende

Deshalb kann Lesen und Lernen manchmal nicht „ohne den Versuch eines gründlichen Verständnisses“ geschehen.

Sie müssen auch mutig genug sein, „herumzustöbern“ und lernen, wie man „Dokumente prüft“ [/lustiges Gesicht].

Zusammenfassen

Dies ist das Ende dieses Artikels über den problematischen JS-Operator. Weitere Informationen zum problematischen JS-Operator finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, Sie werden 123WORDPRESS.COM auch in Zukunft unterstützen!

Das könnte Sie auch interessieren:
  • Diskussion über die Verwendung von Typeof- und Instanceof-Operatoren in JavaScript

<<:  Detaillierte Schritte zum Konfigurieren der MySQL-Remoteverbindung unter Alibaba Cloud

>>:  Sicherheitskonfiguration und Erkennung von SSL, nachdem die Website https aktiviert hat

Artikel empfehlen

Nodejs-Fehlerbehandlungsprozessaufzeichnung

In diesem Artikel wird der Verbindungsfehler ECON...

So erstellen Sie einen MySQL-Cluster mit hoher Verfügbarkeit und Leistung

Inhaltsverzeichnis Was ist MySQL NDB Cluster? Vor...

Der Unterschied zwischen ENTRYPOINT und CMD in Dockerfile

Im Lernprogramm zum Docker-System haben wir geler...

Eine kurze Analyse des Unterschieds zwischen statisch und selbst in PHP-Klassen

Verwenden Sie self:: oder __CLASS__, um eine stat...

Verbesserung der Aktualisierungsfunktion für Zen-Codierungsressourcen

Offizielle Website: http://code.google.com/p/zen-c...

Detaillierte Erklärung des Pufferpools in MySQL

Jeder weiß, dass Daten in MySQL auf die Festplatt...

Auszeichnungssprache - Titel

Klicken Sie hier, um zum Abschnitt „HTML-Tutorial“...

Einführung in die Verwendung von CSS3-Farbwerten (RGBA) und Farbverlaufsfarben

Vor CSS3 konnten Verlaufsbilder nur als Hintergru...

Detaillierte Erläuterung der Vue-Projektoptimierung und -verpackung

Inhaltsverzeichnis Vorwort 1. Lazy Loading-Routin...

Detaillierte Einführung in das CSS-Prioritätswissen

Bevor wir über die CSS-Priorität sprechen, müssen...