Recientemente desarrollé una aplicación móvil html5. La aplicación era una sola página donde los eventos de cambio de hash de navegación reemplazaban a todo el DOM. Una sección de la aplicación era un mapa de Google usando API v3. Antes de que el mapa div se elimine del DOM, quiero eliminar cualquier controlador / escucha de eventos y liberar tanta memoria como sea posible, ya que el usuario no puede volver a esa sección nuevamente.
¿Cuál es la mejor forma de destruir una instancia de mapa?
javascript
google-maps-api-3
Chad Killingsworth
fuente
fuente
Respuestas:
Estoy agregando una segunda respuesta a esta pregunta, porque no quiero eliminar la ida y vuelta que tuvimos a través de los comentarios de seguimiento de mi respuesta anterior.
Pero recientemente encontré información que aborda directamente su pregunta y por eso quería compartirla. No sé si está al tanto de esto, pero durante el video del horario de oficina de la API de Google Maps el 9 de mayo de 2012 , Chris Broadfoot y Luke Mahe de Google discutieron esta misma pregunta de stackoverflow. Si configura la reproducción de video en 12:50, esa es la sección donde discuten su pregunta.
Básicamente, admiten que es un error, pero también añaden que realmente no admiten casos de uso que impliquen la creación / destrucción de instancias de mapas sucesivas. Recomiendan encarecidamente crear una única instancia del mapa y reutilizarla en cualquier escenario de este tipo. También hablan de configurar el mapa en nulo y eliminar explícitamente los detectores de eventos. Expresó su preocupación sobre los oyentes de eventos, pensé que simplemente establecer el mapa en nulo sería suficiente, pero parece que sus preocupaciones son válidas, porque mencionan específicamente a los oyentes de eventos. También recomendaron eliminar por completo el DIV que contiene el mapa.
En cualquier caso, solo quería pasar esto y asegurarme de que esté incluido en la discusión de stackoverflow y espero que te ayude a ti y a otros.
fuente
La respuesta oficial es que no. Las instancias de mapas en una aplicación de una sola página deben reutilizarse y no destruirse y luego recrearse.
Para algunas aplicaciones de una sola página, esto puede significar rediseñar la solución de modo que una vez que se crea un mapa, se pueda ocultar o desconectar del DOM, pero nunca se destruya / vuelva a crear.
fuente
Dado que aparentemente no puede destruir las instancias del mapa, una forma de reducir este problema si
mantiene un grupo de instancias de mapas. El grupo realiza un seguimiento de las instancias que se están utilizando y, cuando se solicita una nueva instancia, verifica si alguna de las instancias de mapa disponibles está libre: si lo está, devolverá una existente, si no lo está, creará una nueva instancia de mapa y devuélvala, agregándola al grupo. De esta manera, solo tendrá un número máximo de instancias igual al número máximo de mapas que haya mostrado simultáneamente en la pantalla. Estoy usando este código (requiere 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 } } }
Le pasa las opciones del mapa de inicio (según el segundo argumento del constructor de google.maps.Map), y devuelve tanto la instancia del mapa (en la que puede llamar a funciones pertenecientes a google.maps.Map) y el contenedor, que puede diseñar usando la clase "myDivClassHereForStyling", y puede agregar dinámicamente al DOM. Si necesita restablecer el sistema, puede usar mapInstancesPool.reset (). Restablecerá el contador a 0, mientras mantiene todas las instancias existentes en el grupo para su reutilización. En mi aplicación, necesitaba eliminar todos los mapas a la vez y crear un nuevo conjunto de mapas, por lo que no hay una función para reciclar una instancia de mapa específica: su kilometraje puede variar. Para eliminar los mapas de la pantalla, utilizo la separación de jQuery, que no destruye el contenedor del mapa.
Al usar este sistema y usar
google.maps.event.clearInstanceListeners(window); google.maps.event.clearInstanceListeners(document);
y corriendo
google.maps.event.clearInstanceListeners(divReference[0]); divReference.detach()
(donde divReference es el objeto jQuery del div devuelto del grupo de instancias) en cada div que estoy eliminando, logré mantener el uso de la memoria de Chrome más o menos estable, en lugar de que aumente cada vez que elimino mapas y agrego nuevos.
fuente
Habría sugerido eliminar el contenido del div del mapa y usarlo
delete
en la variable que contiene la referencia al mapa, y probablemente usar explícitamentedelete
cualquier detector de eventos.Sin embargo, hay un error reconocido y es posible que esto no funcione.
fuente
delete
agreguen mucho (consulte stackoverflow.com/q/742623/1314132 ), pero realmente no puede hacer daño. Al final, todo se reduce a esta pregunta: ¿hay alguna referencia al objeto? Si es así, no se recolectará basura.GUnload()
que eliminar todas las referencias internas de la API.delete
no es realmente una solución. Tienen que arreglar lo grande para que hacer que las referencias sean inalcanzables funcione como debería o agregar una nueva función que proporcione la funcionalidad que usted describeGUnload()
.delete
y borrar lainnerHTML
memoria no borra completamente la memoria. Desafortunadamente, no es un error de alta prioridad.Como Google no proporciona gunload () para api v3, es mejor usar iframe en html y asignar map.html como fuente a este iframe. después de su uso, haga que src sea nulo. Eso definitivamente liberará la memoria consumida por el mapa.
fuente
Cuando quita el
div
, se quita el panel de visualización y el mapa desaparecerá. Para eliminar la instancia del mapa, solo asegúrese de que su referencia al mapa esté establecida ennull
y de que cualquier referencia a otras partes del mapa esté establecida ennull
. En ese momento, la recolección de basura de JavaScript se encargará de la limpieza, como se describe en: ¿Cómo funciona la recolección de basura en JavaScript? .fuente
null
, sino cualquier referencia a cualquier otra cosa. Entonces, si la referencia del marcador está configurada ennull
, haciéndola inalcanzable , no hay forma de llegar al detector de eventos. Es posible que aún esté conectado al mapa, pero no se puede acceder al mapa, por lo que es solo un gran trozo de memoria que esencialmente se ha quedado huérfano. Es lo mismo que establecer unArray.length = 0
; si no hay otras referencias a los miembros, simplemente forman un grupo de memoria huérfana que es elegible para la recolección de basura.Supongo que estás hablando
addEventListener
. Cuando elimina los elementos DOM, algunos navegadores filtran estos eventos y no los eliminan. Es por eso que jQuery hace varias cosas al eliminar un elemento:removeEventListener
. Eso significa que mantiene una matriz con los detectores de eventos que agregó en este elemento.onclick
,onblur
, etc.) utilizandodelete
el elemento DOM cuandoaddEventListener
no está disponible (aún así, tiene una gran variedad donde almacena los eventos añadidos).null
evitar pérdidas de memoria de IE 6/7/8.fuente
removeEventListener
odelete
dependiendo del tipo de evento.