销毁地图实例的正确方法是什么?

IT技术 javascript google-maps-api-3
2021-03-05 06:05:33

我最近开发了一个 html5 移动应用程序。该应用程序是一个页面,其中导航哈希更改事件替换了整个 DOM。该应用程序的一个部分是使用 API v3 的 Google 地图。在从 DOM 中删除地图 div 之前,我想删除所有事件处理程序/侦听器并释放尽可能多的内存,因为用户可能不会再次返回该部分。

销毁地图实例的最佳方法是什么?

6个回答

我在这个问题上添加了第二个答案,因为我不想删除我们通过对我之前的答案的后续评论的来回。

但我最近遇到了一些直接解决您的问题的信息,所以我想分享一下。我不知道您是否意识到这一点,但在2012 年 5 月 9 日Google Maps API 办公时间视频中,来自 Google 的 Chris Broadfoot 和 Luke Mahe 讨论了来自 stackoverflow 的这个问题如果您将视频播放时间设置为 12:50,他们将在该部分讨论您的问题。

本质上,他们承认这是一个错误,但还补充说他们并不真正支持涉及创建/销毁连续地图实例的用例。他们强烈建议创建地图的单个实例并在任何此类场景中重复使用它。他们还谈到将地图设置为 null,并明确删除事件侦听器。您表达了对事件侦听器的担忧,我认为只需将地图设置为 null 就足够了,但看起来您的担忧是有效的,因为它们特别提到了事件侦听器。他们还建议完全删除保存地图的 DIV。

无论如何,只是想传递这个并确保它包含在stackoverflow讨论中,并希望它可以帮助您和其他人 -

好吧,您可以简单地更新上一个答案,并提到这是一个更新...
2021-04-19 06:05:33
太棒了……现在是 2018 年,但似乎仍然没有办法做到这一点。
2021-04-25 06:05:33
谢谢 - 我让他们在办公时间解决这个问题,但还没有机会查看视频。
2021-05-05 06:05:33

官方的回答是你不知道。单页应用程序中的地图实例应该被重用,而不是销毁然后重新创建。

对于某些单页应用程序,这可能意味着重新构建解决方案,这样一旦创建了地图,它就可以隐藏或与 DOM 断开连接,但它永远不会被破坏/重新创建。

这非常糟糕——我有多语言单页应用程序,我想以选定的语言显示谷歌地图。
2021-05-13 06:05:33
看起来这已经在3.38.1 版中得到修复(尽管我还没有独立验证)。
2021-05-14 06:05:33

由于显然您无法真正销毁地图实例,因此可以通过以下方式减少此问题

  • 您需要在一个网站上同时显示多张地图
  • 地图的数量可能会随着用户交互而变化
  • 地图需要与其他组件一起隐藏和重新显示(即它们不会出现在 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,它不会破坏地图的容器。

通过使用该系统,并使用

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调用任何事件侦听器。

但是,一个公认的错误,这可能不起作用。

Chad/Andrew:是的,我已经重现了这个问题,不幸的是delete,清除innerHTML并不能完全清除记忆。不幸的是,这不是一个高优先级的错误。
2021-04-16 06:05:33
@AndrewLeach 绝对。但是如果他们有一个导致内存泄漏的错误,在它得到修复之前我们无能为力。我的意思是,如果使所有地图对象无法访问都不起作用,那么delete这并不是真正的解决方法。他们必须修复大问题,以便使引用无法访问,或者添加一个新函数来提供您所描述的功能GUnload()
2021-04-20 06:05:33
@SeanMickey:这是错误变得相关的地方。版本 2 必须GUnload()删除所有 API 的内部引用。
2021-05-04 06:05:33
我一直在 Chrome 中使用此页面进行测试:people.missouristate.edu/chadkillingsworth/mapsexamples/...到目前为止,删除地图后的内存使用量仅略有下降,但远不及地图实例化之前的水平。
2021-05-08 06:05:33
这是一个很好的讨论。我认为调用不会delete增加太多(参见stackoverflow.com/q/742623/1314132),但它真的不会受到伤害。最后,归结为这个问题:是否有任何对对象的引用?如果是,它不会被垃圾收集。
2021-05-11 06:05:33

由于谷歌没有为 api v3 提供 gunload() 更好地在 html 中使用 iframe 并将 map.html 作为此 iframe 的源。使用后使 src 为空。那肯定会释放地图消耗的内存。

然后,iframe 的每个实例都必须重新加载地图 api,这并不理想。
2021-05-01 06:05:33