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

What is the Proper Way to Destroy a Map Instance?

本文关键字:方法 是什么 地图 实例      更新时间:2023-09-26

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

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

我正在就此问题添加第二个答案,因为我不想删除我们通过对我上一个答案的后续评论来回进行的来回讨论。

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

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

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

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

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

由于显然您无法真正销毁地图实例,因此可以减少此问题的一种方法,如果

  • 您需要在一个网站上一次显示多张地图
  • 地图数量可能会随着用户交互而变化
  • 地图需要隐藏并与其他组件一起重新显示(即它们不会出现在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的构造函数的第二个参数(,它返回map实例(你可以在上面调用与google.maps.Map相关的函数(和容器,你可以使用类"myDivClassHereForStyleing"来设置样式,你可以动态地附加到DOM中。如果需要重置系统,可以使用 mapInstancesPool.reset((。它会将计数器重置为 0,同时保留池中的所有现有实例以供重用。在我的应用程序中,我需要一次删除所有地图并创建一组新的地图,因此没有回收特定地图实例的功能:您的里程可能会有所不同。为了从屏幕中删除地图,我使用了jQuery的分离,它不会破坏地图的容器。

通过使用这个系统,并使用

google.maps.event.clearInstanceListeners(window);
google.maps.event.clearInstanceListeners(document);

和跑步

google.maps.event.clearInstanceListeners(divReference[0]);
divReference.detach()

(其中divReference 是从实例池返回的div 的 jQuery 对象(在我删除的每个div 上,我设法保持 Chrome 的内存使用量或多或少稳定,而不是每次删除地图并添加新地图时都会增加。

我建议删除 mapdiv 的内容并在保存对映射引用的变量上使用 delete,并且可能明确delete任何事件侦听器。

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

由于谷歌没有为 api v3 提供 gunload((,因此最好在 html 中使用 iframe 并分配 map.html 作为此 iframe 的来源。 使用后,将 src 设为空。这肯定会释放地图消耗的内存。

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

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

  • 当可以使用removeEventListener时,它会删除事件。这意味着它保留了一个数组,其中包含它在此元素上添加的事件侦听器。
  • 当 DOM 元素不可用时,它使用 DOM 元素上的delete删除有关事件的属性(addEventListener onclickonblur 等((尽管如此,它仍然有一个数组来存储添加的事件(。
  • 它将元素设置为 null 以避免 IE 6/7/8 内存泄漏。
  • 然后,它会删除该元素。