96

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

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

4

7 回答 7

51

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

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

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

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

于 2012-05-18T22:50:30.547 回答
31

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

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

于 2015-02-02T16:02:30.077 回答
17

由于显然您不能真正销毁地图实例,因此可以减少此问题,如果

  • 您需要在网站上同时显示多张地图
  • 地图的数量可能会随着用户交互而改变
  • 地图需要隐藏并与其他组件一起重新显示(即它们不会出现在 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 的内存使用量或多或少保持稳定,而不是每次我删除地图并添加新地图时它都会增加。

于 2014-08-27T17:08:39.550 回答
5

我会建议删除地图 div 的内容并delete在保存对地图的引用的变量上使用,并且可能显式地deleteing 任何事件侦听器。

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

于 2012-05-07T17:13:01.470 回答
2

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

于 2013-08-23T06:39:52.217 回答
1

当您移除 时div,即移除显示面板并且地图将消失。要删除地图实例,只需确保您对地图的引用设置为null并且对地图其他部分的任何引用都设置为null。那时,JavaScript 垃圾收集将负责清理,如:垃圾收集在 JavaScript 中如何工作?.

于 2012-05-07T16:40:27.023 回答
0

我猜你在说addEventListener. 当您删除 DOM 元素时,某些浏览器会泄漏这些事件并且不会删除它们。这就是为什么 jQuery 在删除元素时会做几件事的原因:

  • 它会在可以使用时删除事件removeEventListener。这意味着它与它在此元素上添加的事件侦听器保持一个数组。
  • 当 DOM 元素不可用时,它会删除有关事件( 、 等)的属性(onclick不过onblur,它有一个数组来存储添加的事件)。deleteaddEventListener
  • 它将元素设置null为避免 IE 6/7/8 内存泄漏。
  • 然后它会删除该元素。
于 2012-05-07T17:08:52.330 回答