Niedawno opracowałem aplikację mobilną html5. Aplikacja była pojedynczą stroną, na której zdarzenia zmiany skrótu nawigacji zastępowały cały DOM. Jedną z sekcji aplikacji była mapa Google wykorzystująca API v3. Zanim element div mapy zostanie usunięty z DOM, chcę usunąć wszystkie programy obsługi / nasłuchiwania zdarzeń i zwolnić jak najwięcej pamięci, ponieważ użytkownik może nie wrócić do tej sekcji ponownie.
Jaki jest najlepszy sposób na zniszczenie instancji mapy?
javascript
google-maps-api-3
Chad Killingsworth
źródło
źródło
Odpowiedzi:
Dodaję drugą odpowiedź na to pytanie, ponieważ nie chcę usuwać tam iz powrotem, które otrzymaliśmy za pośrednictwem dalszych komentarzy do mojej poprzedniej odpowiedzi.
Ale ostatnio natknąłem się na informacje, które bezpośrednio odnoszą się do twojego pytania, więc chciałem się nimi podzielić. Nie wiem, czy zdajesz sobie z tego sprawę, ale podczas godzin pracy w Google Maps API API 9 maja 2012 Video , Chris Broadfoot i Luke Mahe z Google omówili to właśnie pytanie ze stackoverflow. Jeśli ustawisz odtwarzanie wideo na 12:50, to jest sekcja, w której omawiają twoje pytanie.
Zasadniczo przyznają, że jest to błąd, ale dodają również, że tak naprawdę nie obsługują przypadków użycia, które obejmują tworzenie / niszczenie kolejnych instancji mapy. Zdecydowanie zalecają utworzenie jednej instancji mapy i ponowne użycie jej w dowolnym tego rodzaju scenariuszu. Mówią również o ustawieniu mapy na null i jawnym usunięciu detektorów zdarzeń. Wyraziłeś obawy dotyczące detektorów zdarzeń, pomyślałem, że wystarczy ustawić mapę na wartość null, ale wygląda na to, że Twoje obawy są uzasadnione, ponieważ wspominają konkretnie o odbiornikach zdarzeń. Zalecili również całkowite usunięcie DIV, który również trzyma mapę.
W każdym razie chciałem to przekazać i upewnić się, że jest to uwzględnione w dyskusji o przepływie stosu i mam nadzieję, że pomoże to Tobie i innym-
źródło
Oficjalna odpowiedź jest nie. Instancje mapowania w aplikacji jednostronicowej powinny być ponownie używane, a nie niszczone, a następnie odtwarzane.
W przypadku niektórych aplikacji jednostronicowych może to oznaczać zmianę architektury rozwiązania w taki sposób, że po utworzeniu mapy może zostać ukryta lub odłączona od modelu DOM, ale nigdy nie zostanie zniszczona / odtworzona.
źródło
Ponieważ najwyraźniej nie można naprawdę zniszczyć instancji mapy, sposobem na zmniejszenie tego problemu jest, jeśli
zachowuje pulę instancji map. Pula śledzi używane instancje, a gdy zażąda nowej instancji, sprawdza, czy któraś z dostępnych instancji mapy jest wolna: jeśli tak, zwróci istniejącą, jeśli nie, utworzy nową instancję mapy i zwróć ją, dodając ją do puli. W ten sposób będziesz mieć tylko maksymalną liczbę instancji równą maksymalnej liczbie map, które kiedykolwiek pokażesz jednocześnie na ekranie. Używam tego kodu (wymaga 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 } } }
Przekazujesz mu początkowe opcje mapy (zgodnie z drugim argumentem konstruktora google.maps.Map) i zwraca on zarówno instancję mapy (na której można wywoływać funkcje dotyczące google.maps.Map), jak i kontener, który możesz stylizować za pomocą klasy „myDivClassHereForStyling” i możesz dynamicznie dołączać do DOM. Jeśli chcesz zresetować system, możesz użyć mapInstancesPool.reset (). Zresetuje licznik do 0, zachowując wszystkie istniejące instancje w puli do ponownego wykorzystania. W mojej aplikacji musiałem usunąć wszystkie mapy naraz i utworzyć nowy zestaw map, więc nie ma funkcji recyklingu określonej instancji mapy: Twój przebieg może się różnić. Aby usunąć mapy z ekranu, używam detach jQuery, które nie niszczą kontenera mapy.
Korzystając z tego systemu i używając
google.maps.event.clearInstanceListeners(window); google.maps.event.clearInstanceListeners(document);
i bieganie
google.maps.event.clearInstanceListeners(divReference[0]); divReference.detach()
(gdzie divReference to obiekt jQuery div zwrócony z puli instancji) na każdym usuwanym elemencie div udało mi się utrzymać mniej więcej stabilne użycie pamięci Chrome, w przeciwieństwie do zwiększania się za każdym razem, gdy usuwam mapy i dodawałem nowe.
źródło
Sugerowałbym usunięcie zawartości div mapy i użycie
delete
na zmiennej przechowującej odniesienie do mapy i prawdopodobnie jawniedelete
jakichkolwiek detektorów zdarzeń.Istnieje jednak potwierdzony błąd , który może nie działać.
źródło
delete
wiele dodało (patrz stackoverflow.com/q/742623/1314132 ), ale naprawdę nie zaszkodzi. W końcu sprowadza się do pytania: czy są jakieś odniesienia do obiektu? Jeśli tak, nie będzie to śmieci.GUnload()
usunąć wszystkie wewnętrzne odwołania API.delete
to tak naprawdę nie jest poprawką. Muszą naprawić duże, aby uczynić odniesienia nieosiągalnymi działaniami tak, jak powinno, lub dodać nową funkcję, która zapewnia funkcjonalność, którą opisujeszGUnload()
.delete
i wyczyszczenieinnerHTML
nie wyczyści całkowicie pamięci. Niestety nie jest to błąd o wysokim priorytecie.Ponieważ Google nie udostępnia narzędzia gunload () dla interfejsu API v3, lepiej użyj elementu iframe w html i przypisz map.html jako źródło do tego elementu iframe. po użyciu ustaw src na null. To na pewno zwolni pamięć zajmowaną przez mapę.
źródło
Usunięcie
div
ikony spowoduje usunięcie panelu wyświetlania i mapa zniknie. Aby usunąć instancję mapy, po prostu upewnij się, że odniesienie do mapy jest ustawione na,null
a wszelkie odniesienia do innych części mapy są ustawione nanull
. W tym momencie wyrzucanie elementów bezużytecznych JavaScript zajmie się czyszczeniem, jak opisano w: Jak działa czyszczenie pamięci w JavaScript? .źródło
null
, ale wszelkie odniesienia do czegokolwiek innego. Więc jeśli odniesienie do znacznika jest ustawione nanull
, co czyni go nieosiągalnym , nie ma sposobu, aby dotrzeć do detektora zdarzeń. Może nadal być połączony z mapą, ale mapa nie jest dostępna, więc jest to po prostu duża porcja pamięci, która została w zasadzie osierocona. To to samo, co ustawienieArray.length = 0
; jeśli nie ma innych odniesień do członków, po prostu tworzą grupę osieroconej pamięci, która kwalifikuje się do czyszczenia pamięci.Chyba o tym mówisz
addEventListener
. Kiedy usuwasz elementy DOM, niektóre przeglądarki przeciekają te zdarzenia i ich nie usuwają. Dlatego jQuery robi kilka rzeczy podczas usuwania elementu:removeEventListener
. Oznacza to, że przechowuje tablicę z detektorami zdarzeń, które dodała do tego elementu.onclick
,onblur
itp), stosującdelete
na elemencie DOM, gdyaddEventListener
nie jest dostępna (jeszcze, że ma tablicę w której przechowywane są zdarzenia własne).null
aby uniknąć wycieków pamięci IE 6/7/8.źródło
removeEventListener
lub wdelete
zależności od rodzaju zdarzenia.