Який правильний спосіб знищити екземпляр карти?


89

Нещодавно я розробив мобільний додаток html5. Додаток являв собою одну сторінку, де події зміни навігаційного хешу замінили всю DOM. Одним з розділів програми була Google Map із використанням API v3. Перш ніж видалити map з DOM, я хочу видалити всі обробники / прослуховувачі подій і звільнити якомога більше пам'яті, оскільки користувач може не повернутися до цього розділу знову.

Який найкращий спосіб знищити екземпляр карти?


Пов'язаний питання (2014 року): stackoverflow.com/questions/21142483 / ...
kashiraja

Код для спроби видалити всіх прослуховувачів подій на карті, помилка Google Maps 35821412
kashiraja

Відповіді:


48

Я додаю другу відповідь на це питання, тому що я не хочу видаляти туди-сюди, які ми мали через подальші коментарі до моєї попередньої відповіді.

Але нещодавно я натрапив на деяку інформацію, яка безпосередньо стосується вашого питання, і тому я хотів поділитися з нею. Я не знаю, чи знаєте ви про це, але під час роботи Google Maps API 9 травня 2012 року Відео , Кріс Бродфут та Люк Махе з Google обговорили саме це питання від stackoverflow. Якщо ви встановите для відтворення відео 12:50, саме в цьому розділі вони обговорюватимуть ваше запитання.

По суті, вони визнають, що це помилка, але також додають, що насправді не підтримують випадки використання, які передбачають створення / знищення послідовних екземплярів карт. Вони настійно рекомендують створити єдиний екземпляр карти та використовувати її повторно в будь-якому подібному сценарії. Вони також говорять про встановлення нульової карти та явне видалення прослуховувачів подій. Ви висловили занепокоєння щодо слухачів подій, я вважав, що достатньо просто встановити карту на нуль, але, схоже, ваші побоювання є дійсними, оскільки вони конкретно згадують про слухачів подій. Вони також рекомендували повністю видалити DIV, який також містить карту.

У кожному разі, я просто хотів передати це і переконатися, що воно включено в обговорення stackoverflow і сподіваюся, що це допоможе вам та іншим.


2
Дякую - я попросив їх вирішити питання в робочі години, але ще не отримав можливості перевірити відео.
Чад Кіллінгсворт,

Ну, ви могли просто оновити попередню відповідь, згадавши, що це оновлення ...
TJ

4
Ну чудово .. це 2018 рік, і все ще, здається, немає способу зробити це.
JP Silvashy

28

Офіційна відповідь є не потрібно. Екземпляри карти в одностраничній програмі слід використовувати повторно, а не знищувати, а потім відтворювати.

Для деяких односторінкових додатків це може означати реорганізацію рішення таким чином, що після створення карти вона може бути прихована або відключена від DOM, але вона ніколи не руйнується / відтворюється.


Це дуже і дуже погано - у мене є багатомовна односторінкова програма, і я хочу відображати Google Map на вибраній мові.
artuska

14

Оскільки, очевидно, ви дійсно не можете знищити екземпляри карт, спосіб зменшити цю проблему, якщо

  • на веб-сайті потрібно показати відразу кілька карт
  • кількість карт може змінюватися при взаємодії з користувачем
  • карти потрібно приховувати та повторно показувати разом з іншими компонентами (тобто вони не відображаються у фіксованому положенні в 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. Якщо вам потрібно скинути систему, ви можете скористатися mapInsistancePool.reset (). Він скине лічильник на 0, зберігаючи всі наявні екземпляри в пулі для повторного використання. У моїй програмі мені потрібно було видалити всі карти одночасно і створити новий набір карт, тому немає функції переробки конкретного екземпляра карти: ваш пробіг може змінюватися. Щоб видалити карти з екрану, я використовую jQuery's detach, який не руйнує контейнер карти.

Використовуючи цю систему, і використовуючи

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

і працює

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

.


ВИ Врятували моє життя! Thnks;)
Феліпе Десидераті,

Радий допомогти !!
Паоло Міоні

5

Я б запропонував видалити вміст div div і використовувати deleteзмінну, що містить посилання на карту, і, можливо, явно deleteвписати будь-які прослуховувачі подій.

Однак існує визнана помилка , і це може не спрацювати.


Це хороша дискусія. Я не думаю, що дзвінки deleteдодають багато (див. Stackoverflow.com/q/742623/1314132 ), але це насправді не може зашкодити. Зрештою, справа зводиться до цього питання: чи є посилання на об’єкт? Якщо так, це не буде зібране сміття.
Шон Міккі,

1
@SeanMickey: саме тут помилка стає актуальною. Версія 2 GUnload()повинна видалити всі внутрішні посилання на API.
Ендрю Ліч

Я тестував із цією сторінкою в Chrome: people.missouristate.edu/chadkillingsworth/mapsexamples/ ... Поки що використання пам’яті після видалення карти лише незначно падає, але це ще близько до рівня до створення карти.
Чад Кіллінгсворт,

@AndrewLeach Абсолютно. Але якщо у них є помилка, яка спричиняє витік пам'яті, ми не можемо багато чого зробити, поки це не буде виправлено. Я маю на увазі, якщо зробити всі об’єкти карти недосяжними не працює, deleteце насправді не є виправленням. Вони повинні виправити велике, щоб зробити посилання недосяжними, як слід, або додати нову функцію, яка забезпечує функціональність, яку ви описуєте GUnload().
Шон Міккі,

1
Чад / Ендрю: так, я відтворив цю проблему, на жаль deleteі очистивши innerHTMLне зовсім очищену пам'ять. На жаль, це не висока пріоритетна помилка.
Кріс Бродфут

2

Оскільки Google не надає gunload () для api v3, краще використовувати iframe у html та призначити map.html як джерело для цього iframe. після використання зробіть src нульовим. Це точно звільнить пам’ять, споживану картою.


2
Тоді кожному екземпляру iframe доведеться перезавантажити api карт, що не є ідеальним.
Чад Кіллінгсворт,

1

Коли ви видалите div, що видаляє панель дисплея, і карта зникне. Щоб видалити екземпляр карти, просто переконайтеся, що для вашого посилання на карту встановлено значення, nullа для будь-яких посилань на інші частини карти встановлено значення null. На той момент збір сміття JavaScript подбає про очищення, як описано в: Як працює збір сміття в JavaScript? .


1
Я не впевнений, що встановлення значення змінної map на null буде належним чином видалити всі прослуховувачі подій.
Чад Кіллінгсворт,

1
Потрібно встановити не просто карту null, а будь-які посилання на що-небудь інше. Отже, якщо для посилання на маркер встановлено значення null, що робить його недосяжним , неможливо дістатися до слухача події. Можливо, вона все ще підключена до карти, але до неї неможливо дістатись, тож це просто велика частина пам’яті, яка по суті стала сиротою. Це те саме, що встановити Array.length = 0; якщо немає інших посилань на учасників, вони просто утворюють групу осиротілої пам'яті, яка підходить для збору сміття.
Шон Міккі

0

Я думаю, ви говорите про addEventListener. Коли ви видаляєте елементи DOM, деякі браузери витікають із цих подій і не видаляють їх. Ось чому jQuery виконує кілька дій під час видалення елемента:

  • Він видаляє події, коли може використовувати removeEventListener. Це означає, що він зберігає масив із прослуховувачами подій, які він додав до цього елемента.
  • Він видаляє атрибути про події ( onclick, onblurтощо) за допомогою deleteелемента DOM, коли addEventListenerвін недоступний (все-таки він має масив, де зберігає додані події).
  • Він встановлює елемент таким чином, nullщоб уникнути витоків пам'яті IE 6/7/8.
  • Потім він видаляє елемент.

Я в основному маю на увазі внутрішні події API Карт Google. Їх можна додавати / видаляти / запускати за допомогою методів подій API, задокументованих на developers.google.com/maps/documentation/javascript/… . Хоча за функціональністю схожий на браузер addEventListener, існує велика кількість спеціальних подій, характерних для карти (наприклад, "bounds_changed", і деякі з цих обробників подій підключаються до подій браузера, таких як подія "зміна розміру" на карті)
Чад Кіллінгсворт

Потім збережіть масив доданих подій та видаліть їх, а потім вручну, використовуючи removeEventListenerабо deleteзалежно від виду події.
Флоріан Маргайн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.