Уничтожение экземпляра

Жизненный цикл экземпляра Tom Select включает не только инициализацию и работу с данными, но и корректное завершение. Удаление экземпляра требуется при динамических интерфейсах, переходах между страницами в SPA, повторной инициализации компонентов, а также при очистке ресурсов для предотвращения утечек памяти и накопления обработчиков событий.

Основной механизм уничтожения

Базовый способ завершения работы экземпляра реализуется через метод destroy():

const tomSelect = new TomSelect('#select', {
  create: true,
  persist: false
});

// уничтожение экземпляра
tomSelect.destroy();

После вызова destroy() библиотека выполняет комплексное восстановление исходного состояния элемента и очистку всех внутренних структур.


Что происходит при destroy()

Процесс уничтожения включает несколько последовательных этапов:

1. Восстановление оригинального <select>

Tom Select заменяет стандартный <select> кастомной разметкой. При уничтожении выполняется обратная операция:

  • удаляется контейнер Tom Select
  • восстанавливается исходный <select> в DOM
  • сохраняются выбранные значения в стандартном формате

2. Удаление созданной DOM-структуры

Созданные элементы интерфейса полностью удаляются:

  • контейнер .ts-wrapper
  • поле ввода поиска
  • dropdown с результатами
  • элементы выбранных опций (chips/items)
  • вспомогательные элементы управления

Это гарантирует отсутствие «мусора» в DOM после уничтожения.


3. Отписка от событий

Одной из ключевых задач является очистка обработчиков:

  • события клавиатуры (keydown, keyup)
  • события мыши (click, mousedown, mouseover)
  • события фокуса (focus, blur)
  • внутренние события синхронизации состояния

Отсутствие корректной отписки приводит к утечкам памяти, особенно в SPA.


4. Очистка внутренних структур

Удаляются внутренние состояния экземпляра:

  • кеш отфильтрованных опций
  • индексированные списки элементов
  • ссылки на DOM-ноды
  • временные массивы поиска
  • состояния dropdown

После этого объект экземпляра фактически перестаёт быть функциональным.


5. Деактивация плагинов

Если использовались плагины Tom Select, например:

  • remove_button
  • dropdown_input
  • virtual_scroll

они также корректно деинициализируются, освобождая привязанные ресурсы и события.


Повторная инициализация после destroy()

После вызова destroy() исходный <select> снова становится обычным HTML-элементом, что позволяет повторно создать экземпляр:

tomSelect.destroy();

const newInstance = new TomSelect('#select', {
  create: true
});

Важно учитывать, что повторная инициализация должна выполняться только после полного удаления старого экземпляра, иначе возможны дубли DOM-структур.


Уничтожение в динамических интерфейсах

В SPA-приложениях уничтожение экземпляра становится обязательной практикой при смене компонентов.

Пример при смене контейнера

let tsInstance;

function mountSelect() {
  tsInstance = new TomSelect('#select');
}

function unmountSelect() {
  if (tsInstance) {
    tsInstance.destroy();
    tsInstance = null;
  }
}

Уничтожение при замене DOM

При программной замене блока, содержащего <select>, необходимо предварительно уничтожить экземпляр:

function replaceBlock() {
  tsInstance.destroy();

  document.querySelector('#container').innerHTML = `
    <select id="select"></select>
  `;

  tsInstance = new TomSelect('#select');
}

Игнорирование этого шага приводит к «осиротевшим» обработчикам и некорректному поведению интерфейса.


Уничтожение и формы

При работе с формами важно учитывать следующие особенности:

  • значения <select> сохраняются в DOM-элементе
  • после destroy() форма возвращается к стандартному поведению
  • кастомная логика выбора больше не применяется

Пример:

const ts = new TomSelect('#tags');

document.querySelector('form').addEventListener('submit', () => {
  ts.destroy();
});

Частичные ошибки при уничтожении

Неправильное использование destroy часто связано с несколькими сценариями:

Повторный destroy

ts.destroy();
ts.destroy(); // ошибка логики

Второй вызов может приводить к ошибкам, так как экземпляр уже не существует.


Потеря ссылки на экземпляр

new TomSelect('#select').destroy();

В этом случае отсутствует возможность управлять экземпляром после создания, что усложняет контроль жизненного цикла.


Уничтожение и события вне экземпляра

Если события навешивались вручную вне Tom Select, они не удаляются автоматически:

document.addEventListener('click', handler);

После destroy() такие обработчики остаются активными и требуют ручной очистки.


Особенности поведения в повторной инициализации DOM

При частом создании и уничтожении экземпляров следует учитывать:

  • необходимость проверки существования wrapper-элемента
  • отсутствие дубликатов id
  • корректное восстановление исходного <select>
  • синхронизацию значений с внешним состоянием

Сценарии утечек памяти

Наиболее частые причины утечек:

  • сохранение ссылок на уничтоженный экземпляр
  • незавершённые асинхронные операции поиска
  • сторонние события вне Tom Select
  • повторная инициализация без destroy

Управление жизненным циклом в сложных интерфейсах

В интерфейсах с динамическими вкладками или модальными окнами часто используется паттерн «монтаж/размонтирование»:

class SelectController {
  constructor(selector) {
    this.selector = selector;
    this.instance = null;
  }

  mount() {
    this.instance = new TomSelect(this.selector);
  }

  unmount() {
    if (this.instance) {
      this.instance.destroy();
      this.instance = null;
    }
  }
}

Такой подход обеспечивает предсказуемость состояния и исключает накопление ресурсов.


Поведение после destroy()

После уничтожения:

  • DOM возвращается к исходному виду
  • экземпляр становится неработоспособным
  • события библиотеки прекращают работу
  • доступ к методам экземпляра больше не гарантируется

Любые операции над ним после уничтожения считаются некорректными.


Итоговые технические характеристики процесса

  • полная очистка DOM-обёртки
  • восстановление нативного <select>
  • удаление всех внутренних событий
  • освобождение памяти, связанной с экземпляром
  • деактивация плагинов и расширений
  • разрыв связей между UI и моделью данных