Bir Harita Örneğini Yok Etmenin Doğru Yolu Nedir?


92

Yakın zamanda bir html5 mobil uygulaması geliştirdim. Uygulama, gezinme hash değişiklik olaylarının tüm DOM'un yerini aldığı tek bir sayfaydı. Uygulamanın bir bölümü, API v3 kullanan bir Google Haritasıydı. Map div DOM'den kaldırılmadan önce, herhangi bir olay işleyicisini / dinleyicisini kaldırmak ve mümkün olduğunca fazla bellek boşaltmak istiyorum, çünkü kullanıcı o bölüme tekrar dönemeyebilir.

Bir harita örneğini yok etmenin en iyi yolu nedir?



Bir haritadaki tüm olay dinleyicilerini kaldırmaya çalışan kod, Google haritalar hatası 35821412
kashiraja

Yanıtlar:


49

Bu soruya ikinci bir cevap ekliyorum, çünkü önceki cevabımla ilgili takip yorumlarıyla aldığımız geri ve ileri görüşleri kaldırmak istemiyorum.

Ancak son zamanlarda doğrudan sorunuza hitap eden bazı bilgilerle karşılaştım ve bu yüzden paylaşmak istedim. Bunun farkında mısınız bilmiyorum, ancak Google Maps API Ofis Saatleri 9 Mayıs 2012 Videosu sırasında, Google'dan Chris Broadfoot ve Luke Mahe stackoverflow'daki bu soruyu tartıştılar . Video oynatmayı 12:50 olarak ayarlarsanız, sorunuzu tartıştıkları bölüm burasıdır.

Esasen, bunun bir hata olduğunu kabul ediyorlar, ancak art arda harita örnekleri oluşturmayı / yok etmeyi içeren kullanım durumlarını gerçekten desteklemediklerini de ekliyorlar. Haritanın tek bir örneğini oluşturmanızı ve bu türden herhangi bir senaryoda onu yeniden kullanmanızı şiddetle tavsiye ediyorlar. Ayrıca haritayı null olarak ayarlamak ve olay dinleyicilerini açıkça kaldırmak hakkında konuşurlar. Olay dinleyicileriyle ilgili endişelerinizi dile getirdiniz, haritayı boşa ayarlamanın yeterli olacağını düşündüm, ancak endişeleriniz geçerli görünüyor, çünkü özellikle olay dinleyicilerinden bahsediyorlar. Ayrıca haritayı tutan DIV'nin tamamen kaldırılmasını da önerdiler.

Her halükarda, bunu iletmek ve yığın aşımı tartışmasına dahil edilmesini sağlamak ve size ve başkalarına yardımcı olmasını ummak istedim.


2
Teşekkürler - Onlardan soruyu mesai saatlerinde halletmelerini istedim ama henüz videoyu kontrol etme şansım olmadı.
Chad Killingsworth

Bir güncelleme olduğundan bahseden önceki cevabı basitçe güncelleyebilirdiniz ...
TJ

4
Peki harika ... 2018 yılı ve hala bunu yapmanın bir yolu yok gibi görünüyor.
JP Silvashy

28

Resmi cevap da yoktur olduğunu. Tek sayfalı bir uygulamadaki harita örnekleri yeniden kullanılmalı ve yok edilmemeli ve sonra yeniden oluşturulmalıdır.

Bazı tek sayfalı uygulamalar için bu, bir harita oluşturulduktan sonra gizlenebilecek veya DOM ile bağlantısı kesilebilecek, ancak asla yok edilmeyecek / yeniden oluşturulmayacak şekilde çözümün yeniden yapılandırılması anlamına gelebilir.


Bu çok çok kötü - Çok dilli tek sayfa uygulamam var ve Google Haritasını seçilen dilde görüntülemek istiyorum.
artuska

Görünüşe göre bu, 3.38.1 sürümünden itibaren düzeltilmiş (bağımsız olarak doğrulamamış olmama rağmen).
Chrest

15

Görünüşe göre harita örneklerini gerçekten yok edemeyeceğiniz için, bu sorunu azaltmanın bir yolu,

  • bir web sitesinde aynı anda birkaç harita göstermeniz gerekiyor
  • harita sayısı kullanıcı etkileşimiyle değişebilir
  • haritaların diğer bileşenlerle birlikte gizlenmesi ve yeniden gösterilmesi gerekir (yani, DOM'da sabit bir konumda görünmezler)

bir harita örnekleri havuzu tutuyor. Havuz, kullanılan örneklerin izlerini tutar ve yeni bir örnek istendiğinde, mevcut harita örneklerinden herhangi birinin ücretsiz olup olmadığını kontrol eder: eğer öyleyse, mevcut olanı döndürür, değilse, bir yeni harita örneği ve onu havuza ekleyerek döndürür. Bu şekilde, ekranda eşzamanlı olarak gösterdiğiniz maksimum harita sayısına eşit bir maksimum örneğe sahip olacaksınız. Bu kodu kullanıyorum (jQuery gerektirir):

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
    }
 }
}

Başlangıç ​​haritası seçeneklerini (google.maps.Map yapıcısının ikinci bağımsız değişkenine göre) iletirsiniz ve hem harita örneğini (google.maps.Map ile ilgili işlevleri çağırabileceğiniz) hem de kapsayıcıyı döndürür. "myDivClassHereForStyling" sınıfını kullanarak stil oluşturabilir ve dinamik olarak DOM'a ekleyebilirsiniz. Sistemi sıfırlamanız gerekirse, mapInstancesPool.reset () öğesini kullanabilirsiniz. Havuzdaki mevcut tüm örnekleri yeniden kullanım için tutarken sayacı 0'a sıfırlayacaktır. Uygulamamda tüm haritaları bir kerede kaldırmam ve yeni bir harita seti oluşturmam gerekiyordu, bu nedenle belirli bir harita örneğini geri dönüştürmek için bir işlev yok: kilometreniz değişebilir. Haritaları ekrandan kaldırmak için, haritanın kapsayıcısını yok etmeyen jQuery's detach'i kullanıyorum.

Bu sistemi kullanarak ve kullanarak

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

ve koşuyor

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

(divReference, div'in Örnek Havuzundan döndürülen jQuery nesnesidir) kaldırdığım her div'de, haritaları silip yenilerini her eklediğimde artması yerine Chrome'un bellek kullanımını az ya da çok sabit tutmayı başardım.


HAYATIMI KURTARDIN! Thnks;)
Felipe Desiderati

Yardımcı olduğuma sevindim !!
Paolo Mioni

5

Map div içeriğini kaldırmayı ve haritaya deletereferansı tutan değişkeni kullanmayı ve muhtemelen deleteherhangi bir olay dinleyicisini açık bir şekilde kullanmayı önerirdim.

Yine de kabul edilmiş bir hata var ve bu işe yaramayabilir.


Bu iyi bir tartışma. deleteAramanın çok şey kattığını sanmıyorum (bkz. Stackoverflow.com/q/742623/1314132 ), ancak gerçekten zarar veremez. Sonunda, şu soruya geliyor: nesneye herhangi bir referans var mı? Cevabınız evet ise çöp toplanmayacaktır.
Sean Mickey

1
@SeanMickey: hatanın alakalı hale geldiği yer burasıdır. Sürüm 2, GUnload()API'nin tüm dahili referanslarını kaldırmalıdır.
Andrew Leach

Chrome'da şu sayfayla test yapıyorum : people.missouristate.edu/chadkillingsworth/mapsexamples/… Şimdiye kadar, harita kaldırıldıktan sonra bellek kullanımı yalnızca biraz düşüyor, ancak harita somutlaştırılmadan önceki seviyeye yakın bir yerde değil.
Chad Killingsworth

@AndrewLeach Kesinlikle. Ancak bellek sızıntısına neden olan bir hata varsa, düzeltilene kadar yapabileceğimiz pek bir şey yok. Demek istediğim, tüm harita nesnelerini erişilemez yapmak işe yaramazsa, o zaman deletegerçekten bir düzeltme değildir. Referansları erişilemez hale getirmek gerektiği gibi çalışması için büyük olanı düzeltmeleri veya tanımladığınız işlevselliği sağlayan yeni bir işlev eklemeleri gerekir GUnload().
Sean Mickey

1
Chad / Andrew: Evet, maalesef bu sorunu yeniden ürettim deleteve innerHTMLhafızayı tamamen temizlemiyorum. Maalesef bu yüksek öncelikli bir hata değil.
Chris Broadfoot

2

Google, api v3 için gunload () sağlamadığından, html'de iframe kullanın ve bu iframe'e kaynak olarak map.html'yi atayın. kullanımdan sonra src'yi null yapın. Bu, haritanın tükettiği hafızayı kesinlikle boşaltacaktır.


2
İframe'in her bir örneği, ideal olmayan haritalar api'sini yeniden yüklemelidir.
Chad Killingsworth

1

Öğesini kaldırdığınızda div, bu ekran panelini kaldırır ve harita kaybolur. Harita örneğini kaldırmak için, haritaya referansınızın olarak ayarlandığından ve haritanın nulldiğer bölümlerine yapılan referansların olarak ayarlandığından emin olun null. Bu noktada, JavaScript çöp toplama, şu bölümde açıklandığı gibi temizleme ile ilgilenecektir: JavaScript'te çöp toplama nasıl çalışır? .


1
Map değişkeninin null olarak ayarlanmasının tüm olay dinleyicilerini düzgün şekilde kaldıracağından emin değilim.
Chad Killingsworth

1
Ayarlanması gereken sadece harita değil null, başka herhangi bir şeye yapılan göndermeler. Dolayısıyla, işaretçi referansı olarak ayarlanırsa null, erişilemez hale gelirse , olay dinleyicisine ulaşmanın bir yolu yoktur. Hâlâ haritaya bağlı olabilir, ancak haritaya ulaşılamıyor, bu yüzden, esasen öksüz kalmış büyük bir hafıza parçası. Bu, bir Array.length = 0; üyelere başka referanslar yoksa, sadece çöp toplama için uygun bir grup öksüz bellek oluştururlar.
Sean Mickey

0

Sanırım bahsediyorsun addEventListener. DOM öğelerini kaldırdığınızda, bazı tarayıcılar bu olayları sızdırır ve kaldırmaz. Bu nedenle jQuery, bir öğeyi kaldırırken birkaç şey yapar:

  • Kullanabildiği zaman olayları kaldırır removeEventListener. Bu, bu öğeye eklediği olay dinleyicileriyle bir dizi tuttuğu anlamına gelir.
  • DOM öğesinde kullanılamadığında (yine de eklenen olayları depoladığı bir diziye sahiptir ) kullanarak olaylarla ilgili öznitelikleri ( onclick, onblurvb.) deleteSiler addEventListener.
  • Öğeyi, nullIE 6/7/8 bellek sızıntılarını önleyecek şekilde ayarlar .
  • Daha sonra öğeyi kaldırır.

Esas olarak dahili Google Haritalar API etkinliklerinden bahsediyorum. Developers.google.com/maps/documentation/javascript/… adresinde belgelenen API olay yöntemleri kullanılarak eklenebilir / kaldırılabilir / tetiklenebilir . İşlevsellik açısından addEventListener tarayıcıya benzer olsa da, haritaya özgü çok sayıda özel etkinlik vardır ("bounds_changed" gibi ve bu olay işleyicilerinden bazıları harita "yeniden boyutlandırma" olayı gibi tarayıcı olaylarına bağlanır.
Chad Killingsworth

Ardından, eklenen olayların bir dizisini koruyun ve ardından manuel olarak removeEventListenerveya deleteolay türüne bağlı olarak kaldırın .
Florian Margaine
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.