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

MySQL kontrolliert die Anzahl der Versuche, falsche Passwörter einzugeben

1. So überwachen Sie MySQL-Deadlocks in Produktio...

Verbesserung der Wirkung von Hyperlinks im Webdesign und in der Produktion

Hyperlinks ermöglichen es Benutzern, sofort von ei...

Eine kurze Analyse von Kubernetes-Controllern und -Labels

Inhaltsverzeichnis 01 Gemeinsame Controller in k8...

JDBC-Idee: MySQL importieren, um Java-JAR-Paket zu verbinden (Mac)

Vorwort 1. Dieser Artikel verwendet MySQL 8.0 Ver...

Detaillierte Erklärung von Softlinks und Hardlinks in Linux

Inhaltsverzeichnis 1. Grundlegende Speicherung vo...

Zusammenfassung der SQL-Deduplizierungsmethoden

Wenn wir SQL zum Extrahieren von Daten verwenden,...

Deaktivieren der Implementierungseigenschaften für Eingabetextfelder

Heute möchte ich einige sehr nützliche HTML-Tags z...

CSS3 verwendet Animationsattribute, um coole Effekte zu erzielen (empfohlen)

animation-name Animationsname, kann mehrere Werte...

Beispiel für Auslassungspunkte bei Überlauf von mehrzeiligem CSS-Text

Auslassungspunkte werden angezeigt, wenn mehrzeil...

So implementieren Sie das N-Grid-Layout in CSS

Häufige Anwendungsszenarien Die Schnittstellen ak...

Installations-Tutorial zur dekomprimierten Version von MySQL5.7.21 unter Win10

Installieren Sie die entpackte Version von Mysql ...