J'ai récemment développé une application mobile html5. L'application était une page unique où les événements de changement de hachage de navigation remplaçaient l'ensemble du DOM. Une section de l'application était une carte Google utilisant l'API v3. Avant que la map div ne soit supprimée du DOM, je souhaite supprimer tous les gestionnaires / écouteurs d'événements et libérer autant de mémoire que possible car l'utilisateur ne peut pas revenir à cette section.
Quelle est la meilleure façon de détruire une instance de carte?
javascript
google-maps-api-3
Chad Killingsworth
la source
la source
Réponses:
J'ajoute une deuxième réponse à cette question, car je ne veux pas supprimer le va-et-vient que nous avons eu via des commentaires de suivi sur ma réponse précédente.
Mais je suis récemment tombé sur des informations qui répondent directement à votre question et je voulais donc les partager. Je ne sais pas si vous en êtes conscient, mais lors de la vidéo du 9 mai 2012 sur l'API Google Maps , Chris Broadfoot et Luke Mahe de Google ont discuté de cette question de stackoverflow. Si vous réglez la lecture vidéo sur 12h50, c'est la section où ils discutent de votre question.
Essentiellement, ils admettent qu'il s'agit d'un bogue, mais ajoutent également qu'ils ne supportent pas vraiment les cas d'utilisation qui impliquent la création / destruction d'instances de carte successives. Ils recommandent fortement de créer une seule instance de la carte et de la réutiliser dans n'importe quel scénario de ce type. Ils parlent également de définir la carte sur null et de supprimer explicitement les écouteurs d'événements. Vous avez exprimé des inquiétudes à propos des écouteurs d'événements, je pensais que définir la carte sur null suffirait, mais il semble que vos préoccupations soient valables, car elles mentionnent spécifiquement les écouteurs d'événements. Ils ont également recommandé de supprimer complètement le DIV qui contient la carte.
Quoi qu'il en soit, je voulais juste le transmettre et vous assurer qu'il est inclus dans la discussion de stackoverflow et j'espère que cela vous aidera, vous et les autres.
la source
La réponse officielle est que non. Les instances de mappage dans une application à page unique doivent être réutilisées et non détruites puis recréées.
Pour certaines applications à page unique, cela peut signifier une nouvelle architecture de la solution de telle sorte qu'une fois qu'une carte est créée, elle peut être cachée ou déconnectée du DOM, mais elle n'est jamais détruite / recréée.
la source
Comme apparemment, vous ne pouvez pas vraiment détruire les instances de carte, un moyen de réduire ce problème si
conserve un pool d'instances de carte. Le pool garde la trace des instances utilisées, et quand il est demandé une nouvelle instance, il vérifie si l'une des instances de carte disponibles est libre: si c'est le cas, il en retournera une existante, si ce n'est pas le cas, il créera un nouvelle instance de carte et la renvoyer, en l'ajoutant au pool. De cette façon, vous n'aurez qu'un nombre maximum d'instances égal au nombre maximum de cartes que vous affichez simultanément à l'écran. J'utilise ce code (il nécessite jQuery):
var mapInstancesPool = { pool: [], used: 0, getInstance: function(options){ if(mapInstancesPool.used >= mapInstancesPool.pool.length){ mapInstancesPool.used++; mapInstancesPool.pool.push (mapInstancesPool.createNewInstance(options)); } else { mapInstancesPool.used++; } return mapInstancesPool.pool[mapInstancesPool.used-1]; }, reset: function(){ mapInstancesPool.used = 0; }, createNewInstance: function(options){ var div = $("<div></div>").addClass("myDivClassHereForStyling"); var map = new google.maps.Map(div[0], options); return { map: map, div: div } } }
Vous lui transmettez les options de carte de départ (selon le deuxième argument du constructeur de google.maps.Map), et il renvoie à la fois l'instance de la carte (sur laquelle vous pouvez appeler des fonctions relatives à google.maps.Map) et le conteneur, qui vous pouvez styliser en utilisant la classe "myDivClassHereForStyling", et vous pouvez ajouter de façon dynamique au DOM. Si vous devez réinitialiser le système, vous pouvez utiliser mapInstancesPool.reset (). Il réinitialisera le compteur à 0, tout en conservant toutes les instances existantes du pool pour une réutilisation. Dans mon application, j'avais besoin de supprimer toutes les cartes en même temps et de créer un nouvel ensemble de cartes, il n'y a donc pas de fonction pour recycler une instance de carte spécifique: votre kilométrage peut varier. Pour supprimer les cartes de l'écran, j'utilise le détachement de jQuery, qui ne détruit pas le conteneur de la carte.
En utilisant ce système et en utilisant
google.maps.event.clearInstanceListeners(window); google.maps.event.clearInstanceListeners(document);
et courir
google.maps.event.clearInstanceListeners(divReference[0]); divReference.detach()
(où divReference est l'objet jQuery de la div renvoyé par le pool d'instances) sur chaque div que je supprime, j'ai réussi à maintenir l'utilisation de la mémoire de Chrome plus ou moins stable, au lieu de l'augmenter chaque fois que je supprime des cartes et en ajoute de nouvelles.
la source
J'aurais suggéré de supprimer le contenu de la carte div et d'utiliser
delete
la variable contenant la référence à la carte, et probablement explicitementdelete
les écouteurs d'événements.Il y a un bogue reconnu , cependant, et cela peut ne pas fonctionner.
la source
delete
ajoute beaucoup (voir stackoverflow.com/q/742623/1314132 ), mais cela ne peut vraiment pas faire de mal. Au final, cela revient à cette question: y a-t-il des références à l'objet? Si oui, il ne sera pas ramassé.GUnload()
supprimer toutes les références internes de l'API.delete
n'est pas vraiment une solution. Ils doivent corriger le gros pour que rendre les références inaccessibles fonctionne comme il se doit ou ajouter une nouvelle fonction qui fournit la fonctionnalité que vous décrivezGUnload()
.delete
et effacer lainnerHTML
mémoire n'efface pas complètement la mémoire. Malheureusement, ce n'est pas un bogue hautement prioritaire.Comme google ne fournit pas gunload () pour l'api v3, mieux vaut utiliser iframe en html et attribuer map.html comme source à cet iframe. après utilisation, rendre src nul. Cela libérera définitivement la mémoire consommée par la carte.
la source
Lorsque vous supprimez le
div
, cela supprime le panneau d'affichage et la carte disparaît. Pour supprimer l'instance de carte, assurez-vous simplement que votre référence à la carte est définie surnull
et que toutes les références à d'autres parties de la carte sont définies surnull
. À ce stade, le garbage collection JavaScript se chargera du nettoyage, comme décrit dans: Comment le garbage collection fonctionne-t-il en JavaScript? .la source
null
, mais toute référence à autre chose. Donc, si la référence du marqueur est définie surnull
, ce qui la rend inaccessible , il n'y a aucun moyen d'atteindre l'écouteur d'événements. Il est peut-être toujours connecté à la carte, mais la carte ne peut pas être atteinte, c'est donc juste un gros morceau de mémoire qui est essentiellement devenu orphelin. C'est la même chose que de définir unArray.length = 0
; s'il n'y a pas d'autres références aux membres, ils forment simplement un groupe de mémoire orpheline qui est éligible pour le garbage collection.Je suppose que vous parlez
addEventListener
. Lorsque vous supprimez les éléments DOM, certains navigateurs divulguent ces événements et ne les suppriment pas. C'est pourquoi jQuery fait plusieurs choses lors de la suppression d'un élément:removeEventListener
. Cela signifie qu'il garde un tableau avec les écouteurs d'événements qu'il a ajoutés sur cet élément.onclick
,onblur
, etc.) à l' aidedelete
de l'élément DOM lorsqu'iladdEventListener
est pas disponible (encore, il a un tableau dans lequel il stocke les événements ajoutés).null
pour éviter les fuites de mémoire IE 6/7/8.la source
removeEventListener
ou endelete
fonction du type d'événement.