В экосистеме Google Maps JavaScript API событийная модель строится
вокруг подписок на события через
google.maps.event.addListener и связанные методы. Каждое
добавление обработчика возвращает объект типа
MapsEventListener, который становится ключевым элементом
последующего удаления.
Ключевая ошибка при работе с событиями — отсутствие сохранения ссылки на подписку:
const listener = map.addListener('click', (e) => {
console.log(e.latLng.toString());
});
Возвращаемый объект необходимо сохранять, поскольку именно он используется для удаления:
google.maps.event.removeListener(listener);
Если ссылка не сохранена, точечное удаление становится невозможным, и единственным вариантом остаётся массовая очистка.
Удаление отдельного обработчика выполняется через:
google.maps.event.removeListener(listener);
Этот вызов полностью отсоединяет callback от источника события. Важно учитывать, что после удаления объект слушателя становится невалидным, и повторное использование ссылки не имеет смысла.
Для полного сброса всех событий у конкретного экземпляра применяется:
google.maps.event.clearInstanceListeners(map);
Метод удаляет все обработчики, зарегистрированные на объекте, включая внутренние подписки API. Это особенно полезно при уничтожении карты или переинициализации компонента.
Более точечный вариант — удаление всех обработчиков конкретного события:
google.maps.event.clearListeners(map, 'click');
Такой подход сохраняет остальные события, но полностью отключает выбранный тип взаимодействия.
В Google Maps JavaScript API геометрические и графические объекты не
удаляются напрямую через remove() как в DOM. Вместо этого
используется механизм привязки к карте через
setMap(null).
Удаление маркера:
marker.setMap(null);
После этого объект перестаёт отображаться и освобождает ресурсы визуализации. Однако ссылка на объект остаётся в памяти JavaScript до тех пор, пока на него есть внешние ссылки.
Все объекты, наследующие MVCObject, используют
одинаковый механизм:
polyline.setMap(null);
polygon.setMap(null);
circle.setMap(null);
Эти вызовы отключают рендеринг слоя, но не уничтожают объект полностью.
Для наложений и информационных окон используется аналогичный подход:
overlay.setMap(null);
infoWindow.close();
Важно учитывать, что InfoWindow дополнительно
управляется состоянием открытия, поэтому корректная очистка включает
закрытие перед удалением ссылки.
Простое скрытие через setMap(null) не гарантирует
освобождение памяти. Объект остаётся в памяти, если:
Корректная деактивация требует разыменования:
marker.setMap(null);
marker = null;
В структурах данных:
markers.forEach(m => m.setMap(null));
markers.length = 0;
Комбинированные сценарии включают и объекты, и их события:
const listener = marker.addListener('click', handler);
// при удалении
google.maps.event.removeListener(listener);
marker.setMap(null);
marker = null;
Если обработчиков много, используется централизованный реестр:
const listeners = [];
listeners.push(
map.addListener('click', onClick),
marker.addListener('dragend', onDragEnd)
);
listeners.forEach(l => google.maps.event.removeListener(l));
listeners.length = 0;
При пересоздании карты типичная проблема — наложение старых слушателей и объектов на новые экземпляры.
Корректный порядок очистки:
google.maps.event.clearInstanceListeners(map);
markers.forEach(m => {
google.maps.event.clearInstanceListeners(m);
m.setMap(null);
});
markers.length = 0;
map = null;
В Google Maps JavaScript API утечки чаще всего возникают не из-за самой карты, а из-за внешнего кода:
function createMarker(data) {
const marker = new google.maps.Marker({ map, position: data.pos });
marker.addListener('click', () => {
console.log(data); // удерживает data в памяти
});
return marker;
}
Даже после удаления маркера data может оставаться в
памяти из-за замыкания.
window.mapState.markers.push(marker);
Если массив не очищается, объекты продолжают существовать.
Помимо событий карты, часто используются DOM-события:
const btn = document.getElementById('btn');
const handler = () => console.log('click');
btn.addEventListener('click', handler);
Удаление:
btn.removeEventListener('click', handler);
При интеграции с картой важно синхронизировать очистку DOM-слушателей с удалением объектов карты.
В одностраничных приложениях карта может пересоздаваться при навигации. Основная проблема — повторная подписка без очистки предыдущей.
Типовой шаблон очистки при unmount:
function destroyMap() {
google.maps.event.clearInstanceListeners(map);
markers.forEach(m => m.setMap(null));
markers = [];
map = null;
}
Если используется компонентный подход, очистка должна происходить строго в lifecycle-хуке уничтожения компонента.
При большом количестве объектов применяется централизованный менеджер:
class MapManager {
constructor(map) {
this.map = map;
this.markers = [];
this.listeners = [];
}
addMarker(marker) {
this.markers.push(marker);
}
addListener(listener) {
this.listeners.push(listener);
}
clear() {
this.listeners.forEach(l =>
google.maps.event.removeListener(l)
);
this.markers.forEach(m => m.setMap(null));
this.listeners = [];
this.markers = [];
}
}
Такой подход снижает риск «висящих» объектов и неконтролируемых подписок.
Многие объекты API наследуют MVCObject, что означает
наличие внутренней системы наблюдения свойств. Очистка таких объектов
требует внимания к:
При массовом удалении предпочтительно использовать
clearInstanceListeners, так как он охватывает внутренние
подписки API, недоступные через пользовательские ссылки.
setMap(null) без обнуления ссылокКаждая из этих ошибок приводит к накоплению объектов и росту потребления памяти даже при визуально «пустой» карте.