Recentemente, desenvolvi um aplicativo móvel html5. O aplicativo era uma página única em que os eventos de mudança de hash de navegação substituíram todo o DOM. Uma seção do aplicativo era um Google Map usando API v3. Antes que o div do mapa seja removido do DOM, quero remover quaisquer manipuladores / ouvintes de eventos e liberar o máximo de memória possível, pois o usuário não pode retornar a essa seção novamente.
Qual é a melhor maneira de destruir uma instância do mapa?
javascript
google-maps-api-3
Chad Killingsworth
fonte
fonte
Respostas:
Estou adicionando uma segunda resposta a essa pergunta, porque não quero remover as idas e vindas que recebemos por meio de comentários de acompanhamento em minha resposta anterior.
Porém, recentemente me deparei com algumas informações que abordam diretamente sua pergunta e, portanto, gostaria de compartilhar. Não sei se você está ciente disso, mas durante o vídeo do horário comercial da API do Google Maps em 9 de maio de 2012 , Chris Broadfoot e Luke Mahe, do Google, discutiram essa mesma questão do stackoverflow. Se você definir a reprodução do vídeo para 12:50, essa é a seção onde eles discutem sua pergunta.
Essencialmente, eles admitem que é um bug, mas também acrescentam que não suportam casos de uso que envolvam a criação / destruição de instâncias de mapas sucessivas. Eles recomendam fortemente a criação de uma única instância do mapa e a reutilização em qualquer cenário desse tipo. Eles também falam sobre como definir o mapa como nulo e remover explicitamente ouvintes de eventos. Você expressou preocupação sobre os ouvintes de eventos, pensei que apenas definir o mapa como nulo seria suficiente, mas parece que suas preocupações são válidas, porque eles mencionam especificamente os ouvintes de eventos. Eles também recomendaram a remoção completa do DIV que contém o mapa.
De qualquer forma, só queria passar isso adiante e garantir que seja incluído na discussão stackoverflow e espero que ajude você e outros-
fonte
A resposta oficial é não. As instâncias de mapa em um aplicativo de página única devem ser reutilizadas, não destruídas e então recriadas.
Para alguns aplicativos de página única, isso pode significar uma nova arquitetura da solução de forma que, uma vez que um mapa seja criado, ele possa ser escondido ou desconectado do DOM, mas nunca é destruído / recriado.
fonte
Visto que, aparentemente, você não pode realmente destruir as instâncias do mapa, uma maneira de reduzir este problema se
está mantendo um pool de instâncias do mapa. O pool rastreia as instâncias em uso e, quando é solicitada uma nova instância, verifica se alguma das instâncias do mapa disponível está livre: se estiver, retornará uma existente; se não estiver, criará um nova instância do mapa e retorná-la, adicionando-a ao pool. Dessa forma, você terá apenas um número máximo de instâncias igual ao número máximo de mapas que você já mostra simultaneamente na tela. Estou usando este código (requer 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 } } }
Você passa as opções do mapa inicial (de acordo com o segundo argumento do construtor google.maps.Map) e ele retorna a instância do mapa (na qual você pode chamar funções pertencentes a google.maps.Map) e o contêiner, que você pode estilizar usando a classe "myDivClassHereForStyling" e pode anexar dinamicamente ao DOM. Se você precisar reiniciar o sistema, pode usar mapInstancesPool.reset (). Ele redefinirá o contador para 0, enquanto mantém todas as instâncias existentes no pool para reutilização. Em meu aplicativo, precisei remover todos os mapas de uma vez e criar um novo conjunto de mapas, então não há função para reciclar uma instância específica do mapa: sua milhagem pode variar. Para remover os mapas da tela, eu uso o detach do jQuery, que não destrói o contêiner do mapa.
Usando este sistema, e usando
google.maps.event.clearInstanceListeners(window); google.maps.event.clearInstanceListeners(document);
e correndo
google.maps.event.clearInstanceListeners(divReference[0]); divReference.detach()
(onde divReference é o objeto jQuery do div retornado do pool de instâncias) em cada div que estou removendo, consegui manter o uso de memória do Chrome mais ou menos estável, em vez de aumentar toda vez que excluo mapas e adiciono novos.
fonte
Eu teria sugerido remover o conteúdo do div do mapa e usá-lo
delete
na variável que contém a referência ao mapa e, provavelmente, explicitardelete
qualquer ouvinte de evento.Porém, há um bug reconhecido e isso pode não funcionar.
fonte
delete
acrescente muito (consulte stackoverflow.com/q/742623/1314132 ), mas realmente não faz mal. No final, tudo se resume a esta questão: existem referências ao objeto? Se sim, não haverá coleta de lixo.GUnload()
remover todas as referências internas da API.delete
não é realmente um conserto. Eles têm que consertar o grande para que tornar as referências inacessíveis funcione como deveria ou adicionar uma nova função que forneça a funcionalidade que você descreveuGUnload()
.delete
e limpar ainnerHTML
memória não limpa completamente. Infelizmente, não é um bug de alta prioridade.Como o google não fornece gunload () para api v3, é melhor usar iframe em html e atribuir map.html como uma fonte para este iframe. após o uso, torne o src nulo. Isso definitivamente irá liberar a memória consumida pelo mapa.
fonte
Quando você remove o
div
, o painel de exibição é removido e o mapa desaparecerá. Para remover a instância do mapa, apenas certifique-se de que sua referência ao mapa seja definida comonull
e que quaisquer referências a outras partes do mapa sejam definidas comonull
. Nesse ponto, a coleta de lixo do JavaScript cuidará da limpeza, conforme descrito em: Como funciona a coleta de lixo no JavaScript? .fonte
null
, mas qualquer referência a qualquer outra coisa. Portanto, se a referência do marcador for definida comonull
, tornando-o inacessível , não há como acessar o ouvinte do evento. Ele ainda pode estar conectado ao mapa, mas o mapa não pode ser alcançado, então é apenas um grande pedaço de memória que se tornou essencialmente órfão. É o mesmo que definir umArray.length = 0
; se não houver outras referências aos membros, eles apenas formarão um grupo de memória órfã que é elegível para a coleta de lixo.Acho que você está falando
addEventListener
. Quando você remove os elementos DOM, alguns navegadores vazam esses eventos e não os remove. É por isso que o jQuery faz várias coisas ao remover um elemento:removeEventListener
. Isso significa que ele está mantendo uma matriz com os ouvintes de evento adicionados a este elemento.onclick
,onblur
, etc), utilizandodelete
no elemento DOM quandoaddEventListener
não está disponível (ainda, que tem uma matriz onde ele armazena os eventos adicionados).null
para evitar vazamentos de memória do IE 6/7/8.fonte
removeEventListener
oudelete
dependendo do tipo de evento.