什么是销毁地图实例的正确方法?
我最近开发了一个html5移动应用程序。 该应用程序是一个页面导航哈希更改事件取代了整个DOM。 应用程序的一部分是使用API v3的Google Map。 在从DOM中删除地图div之前,我想删除所有事件处理程序/侦听器,并释放尽可能多的内存,因为用户可能不会再返回到该部分。
什么是销毁地图实例的最好方法?
我在这个问题上增加了第二个答案,因为我不想通过后续的回复来解决这个问题。
但是我最近遇到了一些直接解决你的问题的信息,所以我想分享一下。 我不知道你是否意识到这一点,但在谷歌地图API的时候 ,来自Google的Chris Broadfoot和Luke Mahe从stackoverflow讨论了这个问题 。 如果您将video播放设置为12:50,那么他们将讨论您的问题。
从本质上讲,他们承认这是一个错误,但也补充说,他们并不真正支持涉及创build/销毁连续地图实例的用例。 他们强烈build议创build地图的单个实例,并在这种情况下重用它。 他们还讨论了将地图设置为null,并显式移除事件监听器。 你expression了对事件监听者的担忧,我认为只要将地图设置为null就足够了,但是看起来你的担心是有效的,因为他们特别提到了事件监听器。 他们还build议完全删除保存地图的DIV。
无论如何,只是想通过这一点,并确保它包含在stackoverflow讨论中,并希望它可以帮助你和其他人 –
官方的答案是你不。 单个页面应用程序中的地图实例应该被重用,而不是被破坏然后重新创build。
对于某些单页面应用程序,这可能意味着需要重新devise解决scheme,以便一旦创build了一个地图,就可以隐藏或断开与DOM的连接,但不会销毁/重新创build该地图。
由于显然你不能真正销毁地图实例,如果减less这个问题的方法
- 您需要在网站上同时显示多个地图
- 用户交互可能会改变地图的数量
- 地图需要被隐藏并且与其他组件一起重新显示(即,它们不出现在DOM中的固定位置)
保持一个地图实例池。 池保持跟踪正在使用的实例,当它被请求一个新的实例时,它检查是否有任何可用的地图实例是空闲的:如果是,它将返回一个现有的实例,如果不是,它将创build一个新的地图实例并返回它,将其添加到池中。 这样,您将只有最大数量的实例等于您在屏幕上同时显示的最大地图数量。 我正在使用这个代码(它需要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 } } }
你传递它的起始地图选项(根据google.maps.Map的构造函数的第二个参数),并返回地图实例(你可以调用与google.maps.Map有关的函数)和容器,您可以使用“myDivClassHereForStyling”类来设置样式,并且可以将其附加到DOM。 如果您需要重置系统,则可以使用mapInstancesPool.reset()。 它会将计数器重置为0,同时保留池中的所有现有实例以供重用。 在我的应用程序中,我需要一次删除所有的地图,并创build一套新的地图,所以没有function来回收特定的地图实例:您的里程可能会有所不同。 要从屏幕上删除地图,我使用jQuery的detach,它不会破坏地图的容器。
通过使用这个系统,并使用
google.maps.event.clearInstanceListeners(window); google.maps.event.clearInstanceListeners(document);
并运行
google.maps.event.clearInstanceListeners(divReference[0]); divReference.detach()
(其中divReference是从实例池返回的div的jQuery对象)在每个div我删除,我设法保持Chrome的内存使用或多或less稳定,而不是增加每次我删除地图和添加新的。
我会build议删除地图div的内容和使用delete
的variables持有对地图的引用,并可能显式delete
任何事件侦听器。
但是,有一个公认的错误 ,这可能无法正常工作。
由于谷歌不提供gunload()为api v3更好地在html中使用iframe和分配map.html作为源iframe。 使用后使src为空。 这肯定会释放地图消耗的内存。
当你删除div
,删除显示面板和地图将消失。 要移除地图实例,只要确保对地图的引用设置为null
并且对地图其他部分的任何引用都设置为null
。 在这一点上,JavaScript垃圾收集将负责清理,如下所述: 垃圾收集如何在JavaScript中工作? 。
我想你在谈论addEventListener
。 当您删除DOM元素时,一些浏览器泄漏这些事件,并不会删除它们。 这就是为什么jQuery在删除元素时做了几件事情:
- 它可以使用
removeEventListener
删除事件。 这意味着它保持一个数组与它添加在这个元素上的事件监听器。 - 当
addEventListener
不可用时(仍然有一个存储添加的事件的数组),它delete
DOM元素上的delete
关于事件(onclick
,onblur
等)的属性。 - 它将元素设置为
null
以避免IE 6/7/8内存泄漏。 - 然后删除元素。