Was sind die tatsächlichen Verwendungszwecke der WeakMap
in ECMAScript 6 eingeführten Datenstruktur?
Da ein Schlüssel einer schwachen Karte einen starken Verweis auf den entsprechenden Wert erstellt und sicherstellt, dass ein Wert, der in eine schwache Karte eingefügt wurde, niemals verschwindet, solange sein Schlüssel noch aktiv ist, kann er nicht für Memotabellen verwendet werden. Caches oder alles andere, für das Sie normalerweise schwache Referenzen, Karten mit schwachen Werten usw. verwenden würden.
Es scheint mir, dass dies:
weakmap.set(key, value);
... ist nur ein Umweg, um dies zu sagen:
key.value = value;
Welche konkreten Anwendungsfälle fehlen mir?
javascript
ecmascript-6
weakmap
Valderman
quelle
quelle
WeakMap
s kann verwendet werden, um Speicherlecks zu erkennen: stevehanov.ca/blog/?id=148Antworten:
Grundsätzlich
WeakMaps bieten eine Möglichkeit, Objekte von außen zu erweitern, ohne die Speicherbereinigung zu beeinträchtigen. Wann immer Sie ein Objekt erweitern möchten, dies aber nicht können, weil es versiegelt ist - oder von einer externen Quelle -, kann eine WeakMap angewendet werden.
Eine WeakMap ist eine Karte (Wörterbuch), in der die Schlüssel schwach sind. Wenn also alle Verweise auf den Schlüssel verloren gehen und keine Verweise mehr auf den Wert vorhanden sind, kann der Wert durch Müll gesammelt werden. Lassen Sie uns dies zuerst anhand von Beispielen zeigen, dann ein wenig erklären und schließlich mit der tatsächlichen Verwendung abschließen.
Angenommen, ich verwende eine API, die mir ein bestimmtes Objekt gibt:
Jetzt habe ich eine Methode, die das Objekt verwendet:
Ich möchte verfolgen, wie oft die Methode mit einem bestimmten Objekt aufgerufen wurde, und melden, ob es mehr als N Mal vorkommt. Naiv würde man denken, eine Karte zu verwenden:
Dies funktioniert, hat jedoch einen Speicherverlust - wir verfolgen jetzt jedes einzelne Bibliotheksobjekt, das an die Funktion übergeben wird, die verhindert, dass die Bibliotheksobjekte jemals durch Müll gesammelt werden. Stattdessen können wir Folgendes verwenden
WeakMap
:Und das Speicherleck ist weg.
Anwendungsfälle
Einige Anwendungsfälle, die andernfalls einen Speicherverlust verursachen würden und durch
WeakMap
s aktiviert werden, umfassen:Schauen wir uns eine echte Verwendung an
Es kann verwendet werden, um ein Objekt von außen zu erweitern. Lassen Sie uns ein praktisches (angepasstes, reales - um es klar zu machen) Beispiel aus der realen Welt von Node.js geben.
Angenommen, Sie sind Node.js und haben
Promise
Objekte. Jetzt möchten Sie alle derzeit abgelehnten Versprechen verfolgen. Sie möchten jedoch nicht verhindern , dass sie als Müll gesammelt werden, falls keine Verweise darauf vorhanden sind.Jetzt möchten Sie nativen Objekten aus offensichtlichen Gründen keine Eigenschaften hinzufügen - Sie stecken also fest. Wenn Sie Verweise auf die Versprechen einhalten, verursachen Sie einen Speicherverlust, da keine Speicherbereinigung stattfinden kann. Wenn Sie keine Referenzen aufbewahren, können Sie keine zusätzlichen Informationen zu einzelnen Versprechungen speichern. Jedes Schema, bei dem die ID eines Versprechens von Natur aus gespeichert wird, bedeutet, dass Sie einen Verweis darauf benötigen.
Geben Sie WeakMaps ein
WeakMaps bedeuten, dass die Tasten schwach sind. Es gibt keine Möglichkeit, eine schwache Karte aufzuzählen oder alle ihre Werte abzurufen. In einer schwachen Zuordnung können Sie die Daten basierend auf einem Schlüssel speichern. Wenn der Schlüssel Müll sammelt, werden auch die Werte gespeichert.
Dies bedeutet, dass Sie bei einem gegebenen Versprechen den Status darüber speichern können - und dass das Objekt immer noch Müll gesammelt werden kann. Wenn Sie später einen Verweis auf ein Objekt erhalten, können Sie überprüfen, ob Sie einen Status haben, der sich darauf bezieht, und ihn melden.
Dies wurde verwendet , um zu implementieren unhandled Ablehnung Haken von Petka Antonov als dies :
Wir speichern Informationen zu Versprechungen in einer Karte und können wissen, wann ein abgelehntes Versprechen bearbeitet wurde.
quelle
useObj
Beispiel mit aMap
und nicht a verwendenWeakMap
wir das übergebene Objekt als Kartenschlüssel. Das Objekt wird niemals von der Karte entfernt (da wir nicht wissen würden, wann wir das tun sollen), daher gibt es immer einen Verweis darauf und es kann niemals Müll gesammelt werden. Im WeakMap-Beispiel kann das Objekt aus dem gelöscht werden, sobald alle anderen Verweise auf das Objekt verschwunden sindWeakMap
. Wenn Sie immer noch nicht sicher sind, was ich meine, lassen Sie es mich bitte wissencalled
Beispiel ist besser mit jsfiddle.net/f2efbm7z geschrieben und zeigt nicht die Verwendung einer schwachen Karte. Tatsächlich kann es auf insgesamt 6 Arten besser geschrieben werden, die ich unten auflisten werde.p[key_symbol] = data
. oder 2) eindeutige Benennung;p.__key = data
. oder 3) privater Geltungsbereich;(()=>{let data; p.Key = _=>data=_;})()
. oder 4) Proxy mit 1 oder 2 oder 3. oder 5) Ersetzen / Erweitern der Promise-Klasse durch 1 oder 2 oder 3. oder 6) Ersetzen / Erweitern der Promise-Klasse durch ein Tupel der benötigten Mitglieder. - In jedem Fall wird eine schwache Karte nur benötigt, wenn Sie einen speichersensitiven Cache benötigen.Diese Antwort scheint in einem realen Szenario voreingenommen und unbrauchbar zu sein. Bitte lesen Sie es so wie es ist und betrachten Sie es nicht als tatsächliche Option für etwas anderes als Experimentieren
Ein Anwendungsfall könnte sein, es als Wörterbuch für Hörer zu verwenden. Ich habe einen Kollegen, der das getan hat. Es ist sehr hilfreich, weil jeder Zuhörer direkt auf diese Art und Weise ausgerichtet ist. Auf Wiedersehen
listener.on
.Aus abstrakterer Sicht
WeakMap
ist es jedoch besonders leistungsfähig, den Zugriff auf praktisch alles zu entmaterialisieren. Sie benötigen keinen Namespace, um seine Mitglieder zu isolieren, da dies bereits durch die Art dieser Struktur impliziert ist. Ich bin mir ziemlich sicher, dass Sie einige wichtige Speicherverbesserungen vornehmen können, indem Sie awkwards redundante Objektschlüssel ersetzen (obwohl das Dekonstruieren die Arbeit für Sie erledigt).Bevor Sie lesen, was als nächstes kommt
Ich weiß jetzt , meine betonen ist nicht gerade der beste Weg , um das Problem zu lösen und als Benjamin Grünbaum (check out seine Antwort, wenn es nicht bereits über mir ist: p) wies darauf hin, dieses Problem nicht mit einem regulären gelöst worden sein könnte
Map
, da es wäre durchgesickert, daher besteht die HauptstärkeWeakMap
darin, dass es die Speicherbereinigung nicht beeinträchtigt, da sie keine Referenz behalten.Hier ist der aktuelle Code meines Kollegen (danke an ihn für das Teilen)
Vollständige Quelle hier , es geht um das Listener-Management, über das ich oben gesprochen habe (Sie können sich auch die technischen Daten ansehen ).
quelle
WeakMap
funktioniert gut für die Kapselung und das Verstecken von InformationenWeakMap
ist nur für ES6 und höher verfügbar. AWeakMap
ist eine Sammlung von Schlüssel- und Wertepaaren, bei denen der Schlüssel ein Objekt sein muss. Im folgenden Beispiel erstellen wir einWeakMap
mit zwei Elementen:Wir haben die
set()
Methode verwendet, um eine Zuordnung zwischen einem Objekt und einem anderen Element (in unserem Fall eine Zeichenfolge) zu definieren. Wir haben dieget()
Methode verwendet, um das einem Objekt zugeordnete Element abzurufen. Der interessante Aspekt desWeakMap
s ist die Tatsache, dass es einen schwachen Verweis auf den Schlüssel in der Karte enthält. Eine schwache Referenz bedeutet, dass der Garbage Collector bei Zerstörung des Objekts den gesamten Eintrag aus dem entferntWeakMap
und so Speicherplatz freigibt.quelle
𝗠𝗲𝘁𝗮𝗱𝗮𝘁𝗮
Schwache Karten können verwendet werden, um Metadaten zu DOM-Elementen zu speichern, ohne die Speicherbereinigung zu beeinträchtigen oder Kollegen auf Ihren Code zu verärgern. Sie können sie beispielsweise verwenden, um alle Elemente einer Webseite numerisch zu indizieren.
𝗪𝗶𝘁𝗵𝗼𝘂𝘁 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗼𝗿 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗨𝘀𝗶𝗻𝗴 𝗪𝗲𝗮𝗸𝗠𝗮𝗽𝘀 𝗮𝗻𝗱 𝗪𝗲𝗮𝗸𝗦𝗲𝘁𝘀:
𝗧𝗵𝗲 𝗗𝗶𝗳𝗳𝗲𝗿𝗲𝗻𝗰𝗲
Der Unterschied mag vernachlässigbar erscheinen, abgesehen von der Tatsache, dass die Schwachkartenversion länger ist, es gibt jedoch einen großen Unterschied zwischen den beiden oben gezeigten Codeteilen. Im ersten Codeausschnitt ohne schwache Karten speichert der Codeteil Referenzen in jeder Richtung zwischen den DOM-Elementen. Dies verhindert, dass die DOM-Elemente durch Müll gesammelt werden.
(i * i) % len
mag wie ein seltsamer Ball erscheinen, den niemand verwenden würde, aber denken Sie noch einmal darüber nach: Viele Produktionscodes enthalten DOM-Referenzen, die über das gesamte Dokument verteilt sind. Für den zweiten Codeteil kann der Browser beim Entfernen eines Knotens feststellen, dass der Knoten nicht verwendet wird (von Ihrem Code nicht erreichbar), da alle Verweise auf die Elemente schwach sind Löschen Sie es daher aus dem Speicher. Der Grund, warum Sie sich Gedanken über die Speichernutzung und Speicheranker machen sollten (z. B. das erste Codeausschnitt, in dem nicht verwendete Elemente im Speicher gespeichert sind), liegt darin, dass eine höhere Speichernutzung mehr Browser-GC-Versuche bedeutet (um zu versuchen, Speicher freizugeben) Abwenden eines Browserabsturzes) bedeutet langsameres Surferlebnis und manchmal einen Browserabsturz.Für eine Polyfüllung für diese würde ich meine eigene Bibliothek empfehlen ( hier @ github zu finden ). Es ist eine sehr leichte Bibliothek, die sie einfach ohne die viel zu komplexen Frameworks, die Sie in anderen Polyfills finden, polyfill.
~ Viel Spaß beim Codieren!
quelle
elements
und fertig: Es wird GCed. & Re " DOM-Referenzen, die im gesamten Dokument abprallen ", spielt keine Rolle: Sobald der Hauptlink entferntelements
ist, werden alle Rundschreiben-Refs GCed. Wenn Ihr Element Verweise auf Elemente enthält, die es nicht benötigt, korrigieren Sie den Code und setzen Sie den Verweis auf null, wenn Sie mit der Verwendung fertig sind. Es wird GCed. Schwachkarten werden nicht benötigt .elements
auf Null setzen , kann der Browser die Elemente in der ersten Snippet-Situation nicht überprüfen . Dies liegt daran, dass Sie benutzerdefinierte Eigenschaften für die Elemente festlegen und diese Elemente dann weiterhin abgerufen werden können und auf ihre benutzerdefinierten Eigenschaften weiterhin zugegriffen werden kann, wodurch verhindert wird, dass eines von ihnen GC-geprüft wird. Stellen Sie es sich wie eine Kette von Metallringen vor. Wenn Sie Zugriff auf mindestens ein Glied in der Kette haben, können Sie dieses Glied in der Kette festhalten und so verhindern, dass die gesamte Kette von Gegenständen in den Abgrund fällt.Ich verwende
WeakMap
für den Cache die sorgenfreie Speicherung von Funktionen, die unveränderliche Objekte als Parameter verwenden.Das Auswendiglernen ist eine ausgefallene Art zu sagen: "Nachdem Sie den Wert berechnet haben, speichern Sie ihn im Cache, damit Sie ihn nicht erneut berechnen müssen."
Hier ist ein Beispiel:
Code-Snippet anzeigen
Ein paar Dinge zu beachten:
quelle
Ich habe diesen einfachen funktionsbasierten Anwendungsfall / Beispiel für WeakMaps.
Verwalten Sie eine Sammlung von Benutzern
Ich begann mit einem off -
User
Objekt , deren Eigenschaften umfassen einfullname
,username
,age
,gender
und ein Verfahren genannt ,print
das eines vom Menschen lesbare Zusammenfassung der anderen Eigenschaften druckt.Ich habe dann eine Map hinzugefügt, die aufgerufen wird
users
, um eine Sammlung mehrerer Benutzer zu speichern, die von verschlüsselt sindusername
.Das Hinzufügen der Sammlung erforderte außerdem Hilfsfunktionen zum Hinzufügen, Abrufen, Löschen eines Benutzers und sogar eine Funktion zum Drucken aller Benutzer der Vollständigkeit halber.
Wenn
users
der gesamte oben genannte Code beispielsweise in NodeJS ausgeführt wird , enthält nur die Map den Verweis auf die Benutzerobjekte innerhalb des gesamten Prozesses. Es gibt keinen weiteren Verweis auf die einzelnen Benutzerobjekte.Wenn Sie diesen Code als interaktive NodeJS-Shell ausführen, füge ich als Beispiel vier Benutzer hinzu und drucke sie aus:
Fügen Sie Benutzern weitere Informationen hinzu, ohne den vorhandenen Code zu ändern
Angenommen, es ist eine neue Funktion erforderlich, bei der die SMP-Links (Social Media Platform) jedes Benutzers zusammen mit den Benutzerobjekten verfolgt werden müssen.
Der Schlüssel hier ist auch, dass diese Funktion mit minimalem Eingriff in den vorhandenen Code implementiert werden muss.
Dies ist mit WeakMaps folgendermaßen möglich.
Ich füge drei separate WeakMaps für Twitter, Facebook, LinkedIn hinzu.
Eine
getSMPWeakMap
Hilfsfunktion wird einfach hinzugefügt, um die WeakMap zurückzugeben, die dem angegebenen SMP-Namen zugeordnet ist.Eine Funktion zum Hinzufügen eines Benutzer-SMP-Links zur angegebenen SMP-Schwachkarte.
Eine Funktion zum Drucken nur der Benutzer, die auf dem angegebenen SMP vorhanden sind.
Sie können jetzt SMP-Links für die Benutzer hinzufügen, auch mit der Möglichkeit, dass jeder Benutzer einen Link auf mehreren SMPs hat.
... Fortsetzung des vorherigen Beispiels: Ich füge den Benutzern SMP-Links hinzu, mehrere Links für die Benutzer Bill und Sarah, und drucke dann die Links für jedes SMP separat aus:
Angenommen, ein Benutzer wird
users
durch einen Anruf aus der Karte gelöschtdeleteUser
. Dadurch wird der einzige Verweis auf das Benutzerobjekt entfernt. Dadurch wird auch die SMP-Verbindung von allen SMP WeakMaps (von Garbage Collection) gelöscht, da ohne das Benutzerobjekt keine Möglichkeit besteht, auf eine der SMP-Verbindungen zuzugreifen.... Wenn ich mit dem Beispiel fortfahre, lösche ich Benutzer Bill und drucke dann die Links der SMPs aus, mit denen er verbunden war:
Es ist kein zusätzlicher Code erforderlich, um den SMP-Link einzeln und den vorhandenen Code einzeln zu löschen, bevor diese Funktion ohnehin nicht geändert wurde.
Wenn es eine andere Möglichkeit gibt, diese Funktion mit / ohne WeakMaps hinzuzufügen, können Sie dies gerne kommentieren.
quelle