SortableJS — это мощная библиотека для создания интерактивных списков с перетаскиванием элементов (drag-and-drop). Несмотря на её простоту и удобство, некорректное использование может привести к утечкам памяти (memory leaks), особенно в крупных приложениях с динамическими списками. Рассмотрим, как возникают утечки, типичные сценарии и методы их предотвращения.
SortableJS создаёт внутренние обработчики для событий drag-and-drop.
Если экземпляр Sortable удаляется из DOM без вызова метода
destroy(), эти обработчики продолжают существовать в
памяти, удерживая ссылки на DOM-элементы.
let list = document.getElementById('myList');
let sortable = new Sortable(list, {
animation: 150
});
// Позднее удаляем список из DOM
list.remove();
// Без sortable.destroy() обработчики остаются в памяти
Ключевой момент: всегда вызывать
sortable.destroy() перед удалением элемента из DOM.
Опции onAdd, onUpdate,
onRemove и другие колбэки могут содержать ссылки на
DOM-элементы или большие структуры данных. Если объект Sortable не
уничтожен корректно, эти ссылки остаются в памяти.
let sortable = new Sortable(list, {
onAdd: function (evt) {
processElement(evt.item); // Ссылка на элемент сохраняется
}
});
Рекомендация: внутри колбэков избегать хранения ссылок на элементы без явной необходимости, либо очищать их после использования.
clone без очисткиОпция clone позволяет создавать копии элементов при
перетаскивании. Если созданные клоны остаются в DOM или в переменных,
они увеличивают нагрузку на память. В динамических списках это может
привести к накоплению объектов.
let sortable = new Sortable(list, {
group: 'shared',
pull: 'clone'
});
// Каждый drag создает новый элемент-клон
Решение: после завершения операции перетаскивания удалять ненужные клоны вручную.
sortable.destroy();
Вызывает удаление всех внутренних обработчиков событий и очищает ссылки на DOM-элементы. Должен использоваться перед удалением элемента из DOM или при замене контента.
null для очистки
переменныхПосле вызова destroy() рекомендуется обнулять
переменные:
sortable = null;
Это гарантирует, что сборщик мусора сможет освободить память.
Если список создаётся динамически (например, через React или Vue),
важно вызывать destroy() в момент размонтирования
компонента:
useEffect(() => {
let sortable = new Sortable(listRef.current, { animation: 150 });
return () => {
sortable.destroy();
sortable = null;
};
}, []);
Повторная инициализация Sortable на одном и том же элементе без
предварительного destroy() создаёт новые обработчики,
которые накапливаются в памяти. В крупных приложениях это часто
становится причиной утечек.
Позволяет отслеживать рост количества объектов и их удержание в памяти. Полезно для выявления не уничтоженных экземпляров Sortable и элементов DOM.
Сравнение снимков кучи до и после создания/удаления Sortable помогает определить объекты, которые остаются в памяти.
Позволяет отслеживать затраты на события drag-and-drop и выявлять аномально высокое использование памяти при длительном взаимодействии.
destroy() при удалении
элементов.SortableJS предоставляет удобный API, но ответственность за управление памятью лежит на разработчике. Правильное уничтожение экземпляров, контроль за колбэками и внимательная работа с динамическими списками предотвращают накопление ненужных объектов и обеспечивают стабильную работу приложения.