Отладка медленных туров

Intro.js использует DOM-манипуляции для создания подсказок и выделений элементов на странице. При медленной работе туров ключевым фактором становится объем и сложность DOM, частота изменений стилей и анимации, а также использование сторонних скриптов, которые могут блокировать рендеринг.

Для начала стоит включить консольные логи и метрики времени. Использование console.time() и console.timeEnd() вокруг запуска тура позволяет определить, сколько времени занимает инициализация и переход между шагами.

console.time('startTour');
introJs().start();
console.timeEnd('startTour');

Если разница между шагами заметна, имеет смысл исследовать работу функции showStep, которая отвечает за отрисовку каждого шага.


Оптимизация шагов

Каждый шаг тура содержит объект с селектором и текстом:

introJs().setOptions({
  steps: [
    {
      element: '#menu',
      intro: 'Основное меню',
      position: 'right'
    },
    {
      element: '#content',
      intro: 'Основная область контента',
      position: 'bottom'
    }
  ]
});

Важные моменты для производительности:

  • Минимизировать количество шагов — чем больше шагов, тем выше нагрузка на DOM и анимацию.
  • Использовать точные селекторы — избегать универсальных селекторов вроде div или .container *, так как Intro.js ищет элементы на каждой итерации.
  • Отложенная инициализация — если элементы появляются динамически, лучше запускать тур после полной загрузки контента через window.onload или MutationObserver.

Использование асинхронных шагов

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

function waitForElement(selector) {
  return new Promise(resolve => {
    const element = document.querySelector(selector);
    if (element) {
      resolve(element);
    } else {
      const observer = new MutationObserver(() => {
        const el = document.querySelector(selector);
        if (el) {
          resolve(el);
          observer.disconnect();
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
    }
  });
}

waitForElement('#dynamicButton').then(() => introJs().start());

Это предотвращает задержки, связанные с отсутствием элементов в DOM на момент запуска тура.


Настройка анимации и стилей

Intro.js использует CSS-переходы для появления подсказок. Сильное влияние на скорость оказывают сложные CSS-анимации и тени. Для ускорения стоит:

  • Отключить или упростить анимацию через animation: false.
  • Сократить использование box-shadow и фильтров на элементах тура.
  • Использовать GPU-ускоренные свойства (transform: translate3d(...)) вместо top и left.
introJs().setOptions({
  showStepNumbers: true,
  showBullets: false,
  animation: false
});

Отслеживание переходов между шагами

Для контроля времени между шагами применяются события Intro.js:

  • onbeforechange(targetElement) — перед сменой шага.
  • onafterchange(targetElement) — после смены шага.
  • onchange(targetElement) — при смене шага.

Использование этих колбэков позволяет измерять производительность и выявлять узкие места:

introJs().onafterchange(function(target) {
  console.timeEnd(`step-${this._currentStep}`);
}).onbeforechange(function(target) {
  console.time(`step-${this._currentStep}`);
});

Минимизация конфликтов с другими библиотеками

Замедление туров часто связано с конфликтами с другими скриптами, например, jQuery UI, Bootstrap или кастомными обработчиками событий. Для улучшения производительности:

  • Вызывать Intro.js после инициализации всех сторонних компонентов.
  • Избегать прямого изменения DOM элементов тура из сторонних скриптов во время активного тура.
  • Проверять дебаунс или throttle на событиях resize и scroll, чтобы Intro.js не пересчитывал позиции слишком часто.

Локальная отладка и профилирование

Для глубокого анализа используется Performance Tab в Chrome DevTools:

  1. Запустить запись профиля перед стартом тура.
  2. Перейти по всем шагам.
  3. Остановить запись и проанализировать Main thread, Recalculate Style, Layout и Paint.

Особое внимание следует уделять событиям Forced Reflow, возникающим при манипуляции DOM в каждом шаге.


Итоговые рекомендации

  • Сокращать количество и сложность шагов.
  • Использовать точные селекторы и отложенный запуск.
  • Минимизировать CSS-анимации и тяжелые стили.
  • Асинхронно ожидать динамически загружаемые элементы.
  • Использовать события Intro.js для профилирования.
  • Проверять конфликтующие скрипты и события.

Применение этих методов значительно ускоряет медленные туры, снижает нагрузку на браузер и повышает отзывчивость интерфейса.