销毁地图实例的正确方法是啥?
Posted
技术标签:
【中文标题】销毁地图实例的正确方法是啥?【英文标题】:What is the Proper Way to Destroy a Map Instance?销毁地图实例的正确方法是什么? 【发布时间】:2012-05-16 04:01:16 【问题描述】:我最近开发了一个 html5 移动应用程序。该应用程序是一个页面,其中导航哈希更改事件替换了整个 DOM。该应用程序的一部分是使用 API v3 的 Google Map。在从 DOM 中删除地图 div 之前,我想删除所有事件处理程序/侦听器并释放尽可能多的内存,因为用户可能不会再次返回该部分。
销毁地图实例的最佳方法是什么?
【问题讨论】:
相关问题(2014):***.com/questions/21142483/… 尝试删除地图上所有事件监听器的代码,谷歌地图错误35821412 【参考方案1】:我在这个问题上添加了第二个答案,因为我不想删除我们通过后续 cmets 对我之前的答案的来回。
但我最近发现了一些直接解决您的问题的信息,所以我想分享一下。我不知道您是否知道这一点,但在 Google Maps API Office Hours May 9 2012 Video 期间,来自 Google 的 Chris Broadfoot 和 Luke Mahe 讨论了来自 *** 的这个问题。如果您将视频播放设置为 12:50,那是他们讨论您问题的部分。
基本上,他们承认这是一个错误,但也补充说他们并不真正支持涉及创建/销毁连续地图实例的用例。他们强烈建议创建地图的单个实例并在任何此类场景中重用它。他们还谈到将地图设置为 null,并明确删除事件侦听器。您表达了对事件监听器的担忧,我认为只需将地图设置为 null 就足够了,但看起来您的担忧是有效的,因为它们特别提到了事件监听器。他们还建议完全删除包含地图的 DIV。
无论如何,只是想传递这个并确保它包含在 *** 讨论中,并希望它对您和其他人有所帮助-
【讨论】:
谢谢 - 我让他们在办公时间解决这个问题,但还没有机会查看视频。 嗯,你可以简单地更新之前的答案,提到它是一个更新...... 太棒了..现在是 2018 年,似乎仍然没有办法做到这一点。【参考方案2】:official answer 是你不知道的。单页应用程序中的地图实例应该被重用,而不是被销毁然后重新创建。
对于某些单页应用程序,这可能意味着重新构建解决方案,以便地图一旦创建,它可能会被隐藏或与 DOM 断开连接,但永远不会被销毁/重新创建。
【讨论】:
这非常非常糟糕——我有多语言单页应用程序,我想在选定的语言上显示谷歌地图。 这个好像是fixed as of version 3.38.1(虽然我还没有独立验证过)。【参考方案3】:显然你不能真正销毁地图实例,如果
您需要在网站上同时显示多张地图 地图数量可能会随着用户交互而变化 地图需要隐藏并与其他组件一起重新显示(即它们不会出现在 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 相关的函数)和container ,您可以使用“myDivClassHereForStyling”类对其进行样式设置,并且可以动态地附加到 DOM。 如果需要重置系统,可以使用 mapInstancesPool.reset()。它将计数器重置为 0,同时将所有现有实例保留在池中以供重用。 在我的应用程序中,我需要一次删除所有地图并创建一组新地图,因此没有回收特定地图实例的功能:您的里程可能会有所不同。 为了从屏幕上移除地图,我使用了 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 的内存使用量或多或少保持稳定,而不是每次我删除地图并添加新地图时它都会增加。
【讨论】:
【参考方案4】:我会建议删除地图 div 的内容并在保存对地图的引用的变量上使用 delete
,并可能明确地 delete
ing 任何事件侦听器。
虽然有an acknowledged bug,但这可能不起作用。
【讨论】:
这是一个很好的讨论。我不认为打电话给delete
增加了很多(见***.com/q/742623/1314132),但它真的不会受到伤害。最后,归结为这个问题:是否有对对象的引用?如果是,则不会被垃圾回收。
@SeanMickey:这就是错误变得相关的地方。版本 2 有 GUnload()
删除所有 API 的内部引用。
我一直在 Chrome 中测试这个页面:people.missouristate.edu/chadkillingsworth/mapsexamples/… 到目前为止,地图移除后的内存使用量仅略有下降,但远不及地图实例化之前的水平。跨度>
@AndrewLeach 绝对是。但是,如果他们有一个导致内存泄漏的错误,那么在修复之前我们无能为力。我的意思是,如果无法使所有地图对象都无法访问,那么delete
并不是真正的解决方案。他们必须修复大问题,以便使引用无法访问,或者添加一个新函数来提供您为GUnload()
描述的功能。
Chad/Andrew:是的,我已经重现了这个问题,不幸的是delete
并清除innerHTML
并不能完全清除内存。不幸的是,这不是一个高优先级的错误。【参考方案5】:
由于 google 没有为 api v3 提供 gunload(),因此最好在 html 中使用 iframe 并将 map.html 作为该 iframe 的源。使用后将 src 设为 null。这肯定会释放 map 消耗的内存。
【讨论】:
每个 iframe 实例都必须重新加载不理想的地图 api。【参考方案6】:当您移除div
时,即移除显示面板并且地图将消失。要删除地图实例,只需确保您对地图的引用设置为null
,并且对地图其他部分的任何引用设置为null
。届时,javascript 垃圾收集将负责清理,如:How does garbage collection work in JavaScript? 中所述。
【讨论】:
我不确定将 map 变量设置为 null 是否会正确删除所有事件侦听器。 不仅地图必须设置为null
,还包括对其他任何内容的任何引用。因此,如果标记引用设置为null
,使其无法访问,则无法访问事件侦听器。它可能仍然连接到地图,但无法到达地图,所以它只是一大块内存,基本上已经成为孤儿。与设置Array.length = 0
相同;如果没有其他对成员的引用,它们只会形成一组有资格进行垃圾回收的孤立内存。【参考方案7】:
我猜你说的是addEventListener
。当您删除 DOM 元素时,某些浏览器会泄漏这些事件并且不会删除它们。这就是为什么 jQuery 在删除元素时会做几件事的原因:
removeEventListener
时删除事件。这意味着它会使用它在此元素上添加的事件侦听器来保存一个数组。
当 addEventListener
不可用时,它使用 DOM 元素上的 delete
删除有关事件的属性(onclick
、onblur
等)(仍然有一个数组来存储添加的事件)。
它将元素设置为 null
以避免 IE 6/7/8 内存泄漏。
然后删除元素。
【讨论】:
我主要指的是内部的 Google Maps API 事件。可以使用developers.google.com/maps/documentation/javascript/… 中记录的 API 事件方法添加/删除/触发它们。虽然在功能上与浏览器 addEventListener 类似,但有大量特定于地图的自定义事件(例如“bounds_changed”,其中一些事件处理程序会挂钩到浏览器事件,例如地图“resize”事件。 然后根据事件类型使用removeEventListener
或delete
手动添加和删除事件数组。以上是关于销毁地图实例的正确方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章