Ich habe kürzlich eine mobile HTML5-Anwendung entwickelt. Die Anwendung war eine einzelne Seite, auf der Navigations-Hash-Änderungsereignisse das gesamte DOM ersetzten. Ein Abschnitt der Anwendung war eine Google Map mit API v3. Bevor das Map-Div aus dem DOM entfernt wird, möchte ich alle Event-Handler / Listener entfernen und so viel Speicher wie möglich freigeben, da der Benutzer möglicherweise nicht mehr zu diesem Abschnitt zurückkehrt.
Was ist der beste Weg, um eine Karteninstanz zu zerstören?
javascript
google-maps-api-3
Chad Killingsworth
quelle
quelle
Antworten:
Ich füge eine zweite Antwort auf diese Frage hinzu, da ich das Hin und Her, das wir durch nachfolgende Kommentare zu meiner vorherigen Antwort hatten, nicht entfernen möchte.
Aber ich bin kürzlich auf einige Informationen gestoßen, die Ihre Frage direkt ansprechen, und deshalb wollte ich sie teilen. Ich weiß nicht, ob Sie sich dessen bewusst sind, aber während der Videozeiten von Google Maps API am 9. Mai 2012 haben Chris Broadfoot und Luke Mahe von Google genau diese Frage aus dem Stackoverflow besprochen. Wenn Sie die Videowiedergabe auf 12:50 einstellen, wird in diesem Abschnitt Ihre Frage besprochen.
Im Wesentlichen geben sie zu, dass es sich um einen Fehler handelt, fügen aber auch hinzu, dass sie Anwendungsfälle, bei denen aufeinanderfolgende Karteninstanzen erstellt / zerstört werden, nicht wirklich unterstützen. Es wird dringend empfohlen, eine einzelne Instanz der Karte zu erstellen und in jedem Szenario dieser Art wiederzuverwenden. Sie sprechen auch darüber, die Map auf null zu setzen und Ereignis-Listener explizit zu entfernen. Sie haben Bedenken hinsichtlich der Ereignis-Listener geäußert. Ich dachte, es würde ausreichen, nur die Karte auf Null zu setzen, aber es sieht so aus, als wären Ihre Bedenken berechtigt, da sie speziell Ereignis-Listener erwähnen. Sie empfahlen auch, den DIV, der auch die Karte enthält, vollständig zu entfernen.
Auf jeden Fall wollte ich dies nur weitergeben und sicherstellen, dass es in der Stackoverflow-Diskussion enthalten ist, und hoffe, dass es Ihnen und anderen hilft.
quelle
Die offizielle Antwort lautet: Nicht. Karteninstanzen in einer Einzelseitenanwendung sollten wiederverwendet und nicht zerstört und dann neu erstellt werden.
Für einige Anwendungen mit nur einer Seite kann dies bedeuten, dass die Lösung so umgestaltet wird, dass eine erstellte Karte nach dem Erstellen möglicherweise ausgeblendet oder vom DOM getrennt wird, jedoch niemals zerstört / neu erstellt wird.
quelle
Da Sie anscheinend Karteninstanzen nicht wirklich zerstören können, können Sie dieses Problem reduzieren, wenn
hält einen Pool von Karteninstanzen. Der Pool verfolgt die verwendeten Instanzen und prüft, wenn eine neue Instanz angefordert wird, ob eine der verfügbaren Karteninstanzen frei ist. Wenn dies der Fall ist, wird eine vorhandene Instanz zurückgegeben. Wenn dies nicht der Fall ist, wird eine erstellt neue Karteninstanz und geben Sie sie zurück und fügen Sie sie dem Pool hinzu. Auf diese Weise haben Sie nur eine maximale Anzahl von Instanzen, die der maximalen Anzahl von Karten entspricht, die Sie jemals gleichzeitig auf dem Bildschirm anzeigen. Ich verwende diesen Code (es erfordert jQuery):
Sie übergeben ihm die Startkartenoptionen (gemäß dem zweiten Argument des Konstruktors von google.maps.Map) und es wird sowohl die Karteninstanz (auf der Sie Funktionen für google.maps.Map aufrufen können) als auch der Container zurückgegeben Sie können mit der Klasse "myDivClassHereForStyling" stylen und an das DOM anhängen. Wenn Sie das System zurücksetzen müssen, können Sie mapInstancesPool.reset () verwenden. Der Zähler wird auf 0 zurückgesetzt, während alle vorhandenen Instanzen im Pool zur Wiederverwendung aufbewahrt werden. In meiner Anwendung musste ich alle Karten auf einmal entfernen und einen neuen Kartensatz erstellen, damit es keine Funktion zum Recyceln einer bestimmten Karteninstanz gibt: Ihr Kilometerstand kann variieren. Um die Karten vom Bildschirm zu entfernen, verwende ich jQuerys Detach, wodurch der Container der Karte nicht zerstört wird.
Mit diesem System und mit
und läuft
(wobei divReference das jQuery-Objekt des div ist, das aus dem Instanzpool zurückgegeben wird) Bei jedem Div, das ich entferne, konnte ich die Speichernutzung von Chrome mehr oder weniger stabil halten, anstatt sie jedes Mal zu erhöhen, wenn ich Karten lösche und neue hinzufüge.
quelle
Ich hätte vorgeschlagen, den Inhalt des Map-Div zu entfernen und
delete
die Variable zu verwenden, die den Verweis auf die Map enthält, und wahrscheinlichdelete
alle Ereignis-Listener explizit zu verwenden .Es gibt jedoch einen anerkannten Fehler , der möglicherweise nicht funktioniert.
quelle
delete
viel hinzufügt (siehe stackoverflow.com/q/742623/1314132 ), aber es kann wirklich nicht schaden. Am Ende kommt es auf die Frage an: Gibt es Verweise auf das Objekt? Wenn ja, wird kein Müll gesammelt.GUnload()
alle internen Referenzen der API entfernen.delete
ist das keine wirkliche Lösung. Sie müssen das Problem beheben, damit die Referenzen nicht mehr erreichbar sind, oder eine neue Funktion hinzufügen, die die von Ihnen beschriebene Funktionalität bietetGUnload()
.delete
und das Löschen desinnerHTML
nicht vollständig gelöschten Speichers. Leider ist es kein Fehler mit hoher Priorität.Da Google gunload () für API v3 nicht bereitstellt, verwenden Sie Iframe besser in HTML und weisen Sie diesem Iframe map.html als Quelle zu. Nach Gebrauch mache src als null. Dadurch wird definitiv der von der Karte verbrauchte Speicher freigegeben.
quelle
Wenn Sie das entfernen
div
, wird das Anzeigefeld entfernt und die Karte verschwindet. Um die Karteninstanz zu entfernen, stellen Sie einfach sicher, dass Ihr Verweis auf die Karte aufnull
und alle Verweise auf andere Teile der Karte auf gesetzt sindnull
. Zu diesem Zeitpunkt kümmert sich die JavaScript-Speicherbereinigung um die Bereinigung, wie in: Wie funktioniert die Speicherbereinigung in JavaScript? .quelle
null
, sondern auch Verweise auf etwas anderes. Wenn die Markierungsreferenz auf gesetztnull
ist und nicht erreichbar ist, kann der Ereignis-Listener nicht erreicht werden. Es ist möglicherweise immer noch mit der Karte verbunden, aber die Karte kann nicht erreicht werden. Es handelt sich also nur um einen großen Teil des Speichers, der im Wesentlichen verwaist ist. Es ist das gleiche wie das Setzen einesArray.length = 0
; Wenn keine weiteren Verweise auf die Mitglieder vorhanden sind, bilden sie lediglich eine Gruppe verwaister Speicher, die für die Speicherbereinigung berechtigt sind.Ich denke du redest
addEventListener
. Wenn Sie die DOM-Elemente entfernen, verlieren einige Browser diese Ereignisse und entfernen sie nicht. Aus diesem Grund führt jQuery beim Entfernen eines Elements verschiedene Aktionen aus:removeEventListener
. Das bedeutet, dass ein Array mit den Ereignis-Listenern beibehalten wird, die es zu diesem Element hinzugefügt hat.onclick
,onblur
, usw.) unter Verwendung vondelete
auf dem DOM - Elemente , wennaddEventListener
nicht verfügbar ist (still, es hat eine Anordnung , wo es die Ereignisse speichert hinzugefügt).null
, dass Speicherlecks im IE 6/7/8 vermieden werden.quelle
removeEventListener
oderdelete
abhängig von der Art des Ereignisses.