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

Vue-Router-Verlaufsmodus, serverseitiger Konfigurationsprozess-Datensatz

Geschichtsroute Der Verlaufsmodus bezieht sich au...

Analysieren Sie, wie eine SQL-Abfrageanweisung in MySQL ausgeführt wird

Inhaltsverzeichnis 1. Übersicht über die logische...

Über Zabbix Admin-Login vergessen Passwort zurücksetzen

Das Problem beim Zurücksetzen des Passworts für d...

Implementierung zum Zeichnen einer Audio-Wellenform mit wavesurfer.js

1. Sehen Sie sich die Renderings an Weiterleiten ...

So verwenden Sie die asynchrone Anforderungs-API von Axios in Vue

Inhaltsverzeichnis Einrichten einer einfachen HTT...

So vereinfachen Sie Redux mit Redux Toolkit

Inhaltsverzeichnis Probleme, die Redux Toolkit lö...

Website-Homepage-Design im Illustrationsstil Neuer Trend im Website-Design

Sie können sehen, dass ihre visuellen Effekte sehr...

Verwendung von Kubernetes YAML-Dateien

Inhaltsverzeichnis 01 Einführung in YAML-Dateien ...

So erstellen Sie SonarQube mit Docker

Inhaltsverzeichnis 1. Docker installieren 2. Sona...

Detaillierte Erklärung eines einfachen Schneeeffektbeispiels mit JS

Inhaltsverzeichnis Vorwort Hauptimplementierungsc...

33 Eis- und Schnee-Schriftarten zum Download empfohlen (privat und kommerziell)

01 Winterflocken (nur einzeln) 02 Snowtop Caps (k...

Eine kurze Analyse der Konfigurationselemente des Angular CLI-Releasepfads

Vorwort Bei der Projektfreigabe ist immer eine Ve...

Eine kurze Analyse von Linux resolv.conf

1. Einleitung resolv.conf ist die Konfigurationsd...