我最近开发了一个 html5 移动应用程序。该应用程序是一个页面,其中导航哈希更改事件替换了整个 DOM。该应用程序的一部分是使用 API v3 的 Google Map。在从 DOM 中删除地图 div 之前,我想删除任何事件处理程序/侦听器并释放尽可能多的内存,因为用户可能不会再次返回该部分。
销毁地图实例的最佳方法是什么?
我最近开发了一个 html5 移动应用程序。该应用程序是一个页面,其中导航哈希更改事件替换了整个 DOM。该应用程序的一部分是使用 API v3 的 Google Map。在从 DOM 中删除地图 div 之前,我想删除任何事件处理程序/侦听器并释放尽可能多的内存,因为用户可能不会再次返回该部分。
销毁地图实例的最佳方法是什么?
我在这个问题上添加了第二个答案,因为我不想删除我们通过对我之前的答案的后续评论所获得的来回。
但是我最近遇到了一些直接解决您的问题的信息,所以我想分享一下。我不知道您是否知道这一点,但在2012 年 5 月 9 日的 Google Maps API Office Hours Video中,来自 Google 的 Chris Broadfoot 和 Luke Mahe从 stackoverflow讨论了这个问题。如果您将视频播放设置为 12:50,那是他们讨论您问题的部分。
本质上,他们承认这是一个错误,但也补充说他们并不真正支持涉及创建/销毁连续地图实例的用例。他们强烈建议创建地图的单个实例并在任何此类场景中重用它。他们还谈到将地图设置为 null,并明确删除事件侦听器。您表达了对事件侦听器的担忧,我认为只需将地图设置为 null 就足够了,但看起来您的担忧是有效的,因为它们特别提到了事件侦听器。他们还建议完全删除包含地图的 DIV。
无论如何,只是想传递它并确保它包含在 stackoverflow 讨论中,并希望它对您和其他人有所帮助-
官方的回答是你没有。单页应用程序中的地图实例应该被重用,而不是被销毁然后重新创建。
对于某些单页应用程序,这可能意味着重新构建解决方案,以便一旦创建地图,它可能会被隐藏或与 DOM 断开连接,但永远不会被销毁/重新创建。
由于显然您不能真正销毁地图实例,因此可以减少此问题,如果
正在保留一个地图实例池。池跟踪正在使用的实例,当它被请求一个新实例时,它会检查是否有任何可用的地图实例是空闲的:如果是,它将返回一个现有的实例,如果不是,它将创建一个新的地图实例并返回它,将其添加到池中。这样,您将只有最大数量的实例等于您在屏幕上同时显示的最大地图数量。我正在使用这段代码(它需要 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,同时保留池中的所有现有实例以供重用。在我的应用程序中,我需要一次删除所有地图并创建一组新地图,因此没有回收特定地图实例的功能:您的里程可能会有所不同。为了从屏幕上移除地图,我使用了 jQuery 的 detach,它不会破坏地图的 container 。
通过使用这个系统,并使用
google.maps.event.clearInstanceListeners(window);
google.maps.event.clearInstanceListeners(document);
并运行
google.maps.event.clearInstanceListeners(divReference[0]);
divReference.detach()
(其中 divReference 是从实例池返回的 div 的 jQuery 对象)在我删除的每个 div 上,我设法使 Chrome 的内存使用量或多或少保持稳定,而不是每次我删除地图并添加新地图时它都会增加。
我会建议删除地图 div 的内容并delete
在保存对地图的引用的变量上使用,并且可能显式地delete
ing 任何事件侦听器。
但是,有一个公认的错误,这可能不起作用。
由于谷歌没有为 api v3 提供 gunload() 更好地在 html 中使用 iframe 并将 map.html 作为该 iframe 的源。使用后将 src 设为 null。这肯定会释放 map 消耗的内存。
当您移除 时div
,即移除显示面板并且地图将消失。要删除地图实例,只需确保您对地图的引用设置为null
并且对地图其他部分的任何引用都设置为null
。那时,JavaScript 垃圾收集将负责清理,如:垃圾收集在 JavaScript 中如何工作?.
我猜你在说addEventListener
. 当您删除 DOM 元素时,某些浏览器会泄漏这些事件并且不会删除它们。这就是为什么 jQuery 在删除元素时会做几件事的原因:
removeEventListener
。这意味着它与它在此元素上添加的事件侦听器保持一个数组。onclick
不过onblur
,它有一个数组来存储添加的事件)。delete
addEventListener
null
为避免 IE 6/7/8 内存泄漏。