简体   繁体   English

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

[英]What is the Proper Way to Destroy a Map Instance?

I recently developed an html5 mobile application. 我最近开发了html5移动应用程序。 The application was a single page where navigation hash change events replaced the entire DOM. 该应用程序是一个页面,其中导航哈希更改事件替换了整个DOM。 One section of the application was a Google Map using API v3. 该应用程序的一部分是使用API​​ v3的Google Map。 Before the map div is removed from the DOM, I want to remove any event handlers/listeners and free up as much memory as possible as the user may not return to that section again. 在从DOM中删除map div之前,我想删除所有事件处理程序/侦听器,并释放尽可能多的内存,因为用户可能不会再次返回该部分。

What is the best way to destroy a map instance? 销毁地图实例的最佳方法是什么?

I'm adding a second answer on this question, because I don't want to remove the back and forth we had via follow-up comments on my previous answer. 我要在这个问题上添加第二个答案,因为我不想通过对先前答案的后续评论来回删除。

But I recently came across some information that directly addresses your question and so I wanted to share. 但是我最近遇到了一些直接解决您问题的信息,因此我想分享一下。 I don't know if you are aware of this, but during the Google Maps API Office Hours May 9 2012 Video , Chris Broadfoot and Luke Mahe from Google discussed this very question from stackoverflow. 我不知道您是否知道这一点,但是在Google Maps API办公时间2012年5月9日视频中 ,来自Google的Chris Broadfoot和Luke Mahe从stackoverflow讨论了这个问题 If you set the video playback to 12:50, that is the section where they discuss your question. 如果将视频播放设置为12:50,则这是他们讨论问题的部分。

Essentially, they admit that it is a bug, but also add that they don't really support use cases that involve creating/destroying successive map instances. 从本质上讲,他们承认这是一个错误,但同时补充说,他们并不真正支持涉及创建/销毁连续地图实例的用例。 They strongly recommend creating a single instance of the map and reusing it in any scenario of this kind. 他们强烈建议创建单个地图实例,并在任何这种情况下重新使用它。 They also talk about setting the map to null, and explicitly removing event listeners. 他们还讨论将地图设置为null,并显式删除事件侦听器。 You expressed concerns about the event listeners, I thought just setting the map to null would suffice, but it looks like your concerns are valid, because they mention event listeners specifically. 您表达了对事件侦听器的担忧,我认为仅将map设置为null就足够了,但是看起来您的担忧是有效的,因为它们特别提到了事件侦听器。 They also recommended completely removing the DIV that holds the map as well. 他们还建议完全删除保存地图的DIV。

At any rate, just wanted to pass this along and make sure it is included in the stackoverflow discussion and hope it helps you and others- 无论如何,只是想将其传递并确保它已包括在stackoverflow讨论中,并希望它对您和其他人有帮助-

The official answer is you don't. 官方的答案是你不知道。 Map instances in a single page application should be reused and not destroyed then recreated. 单页应用程序中的地图实例应被重用,并且不被销毁然后重新创建。

For some single page applications, this may mean re-architecting the solution such that once a map is created it may be hidden or disconnected from the DOM, but it is never destroyed/recreated. 对于某些单页应用程序,这可能意味着重新架构解决方案,以便一旦创建了地图,就可以将其隐藏或与DOM断开连接,但永远不要销毁/重新创建它。

Since apparently you cannot really destroy map instances, a way to reduce this problem if 由于您显然无法真正销毁地图实例,因此可以通过以下方法减少此问题:

  • you need to show several maps at once on a website 您需要在网站上一次显示多张地图
  • the number of maps may change with user interaction 地图数量可能会随着用户互动而改变
  • the maps need to be hidden and re-shown together with other components (ie they do not appear in a fixed position in the DOM) 需要隐藏地图并将其与其他组件一起重新显示(即,它们不会出现在DOM中的固定位置)

is keeping a pool of map instances. 正在保留地图实例池。 The pool keeps tracks of instances being used, and when it is requested a new instance, it checks if any of the available map instances is free: if it is, it will return an existing one, if it is not, it will create a new map instance and return it, adding it to the pool. 该池会跟踪正在使用的实例,并在请求一个新实例时会检查是否有可用的地图实例可用:如果可用,它将返回一个现有的实例,如果不是,它将创建一个实例。新的地图实例并将其返回,并将其添加到池中。 This way you will only have a maximum number of instances equal to the maximum number of maps you ever show simultaneously on screen. 这样,您的最大实例数将等于您在屏幕上同时显示的最大地图数。 I'm using this code (it requires jQuery): 我正在使用此代码(它需要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
    }
 }
}

You pass it the starting map options (as per the second argument of google.maps.Map's constructor), and it returns both the map instance (on which you can call functions pertaining to google.maps.Map), and the container , which you can style using the class "myDivClassHereForStyling", and you can dinamically append to the DOM. 您向其传递起始地图选项(根据google.maps.Map的构造函数的第二个参数),它返回地图实例(您可以在其上调用与google.maps.Map有关的函数)和容器(您可以使用“ myDivClassHereForStyling”类设置样式,并且可以动态地附加到DOM。 If you need to reset the system, you can use mapInstancesPool.reset(). 如果需要重置系统,则可以使用mapInstancesPool.reset()。 It will reset the counter to 0, while keeping all existing instances in the pool for reuse. 它将计数器重置为0,同时保留池中所有现有实例以供重用。 In my application I needed to remove all maps at once and create a new set of maps, so there's no function to recycle a specific map instance: your mileage may vary. 在我的应用程序中,我需要立即删除所有地图并创建一组新地图,因此没有回收特定地图实例的功能:您的行驶里程可能会有所不同。 To remove the maps from the screen, I use jQuery's detach, which doesn't destroy the map's container . 为了从屏幕上删除地图,我使用jQuery的detach,它不会破坏地图的container。

By using this system, and using 通过使用该系统,并使用

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

and running 并运行

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

(where divReference is the div's jQuery object returned from the Instance Pool) on every div I'm removing, I managed to keep Chrome's memory usage more or less stable, as opposed to it increasing every time I delete maps and add new ones. (其中divReference是从实例池返回的div的jQuery对象)在我要删除的每个div上,我设法使Chrome的内存使用情况大致保持稳定,而不是每次删除地图并添加新地图时都会增加。

I would have suggested removing the content of the map div and using delete on the variable holding the reference to the map, and probably explicitly delete ing any event listeners. 我建议删除映射div的内容,并在保存引用的变量上使用delete ,并可能明确delete所有事件侦听器。

There is an acknowledged bug , though, and this may not work. 但是,存在一个已确认的错误 ,这可能无法正常工作。

As google doesnt provide gunload() for api v3 better use iframe in html and assign map.html as a source to this iframe. 由于google不为api v3提供gunload(),因此最好在html中使用iframe并将map.html分配为该iframe的源。 after use make src as null. 使用后,使src为null。 That will definitely free the memory consumed by map. 这肯定会释放map消耗的内存。

When you remove the div , that removes the display panel and the map will disappear. 删除div ,将删除显示面板,地图将消失。 To remove the map instance, just make sure that your reference to the map is set to null and that any references to other parts of the map are set to null . 要删除地图实例,只需确保将对地图的引用设置为null并将对地图其他部分的所有引用设置为null At that point, JavaScript garbage collection will take care of cleaning up, as described in: How does garbage collection work in JavaScript? 届时,JavaScript垃圾收集将负责清理工作,如以下内容所述: 垃圾收集如何在JavaScript中工作? .

I guess you're talking about addEventListener . 我猜您在谈论addEventListener When you remove the DOM elements, some browsers leak these events and doesn't remove them. 当您删除DOM元素时,某些浏览器会泄漏这些事件,而不会将其删除。 This is why jQuery does several things when removing an element: 这就是为什么jQuery在删除元素时会做几件事的原因:

  • It removes the events when it can using removeEventListener . 当可以使用removeEventListener时,它将删除事件。 That means it's keeping an array with the event listeners it added on this element. 这意味着它将与添加到此元素的事件侦听器保持数组。
  • It deletes the attributes about events ( onclick , onblur , etc) using delete on the DOM element when addEventListener is not available (still, it has an array where it stores the events added). addEventListener不可用时(仍然具有一个数组,用于存储添加的事件),它将在DOM元素上使用delete事件的属性( onclickonblur等)。
  • It sets the element to null to avoid IE 6/7/8 memory leaks. 它将元素设置为null以避免IE 6/7/8内存泄漏。
  • It then removes the element. 然后将其删除。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM