Velocity.State

Velocity.State — внутренний объект библиотеки Velocity.js, предназначенный для хранения глобального состояния анимационного движка. Он не является частью публичного API в строгом смысле, но активно используется внутри библиотеки для оптимизации производительности, управления очередями анимаций и отслеживания текущего состояния DOM-элементов.

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


Структура объекта Velocity.State

Velocity.State представляет собой единый объект, содержащий несколько ключевых свойств:

Velocity.State = {
    isMobile: false,
    isAndroid: false,
    isGingerbread: false,
    isChrome: true,
    isFirefox: false,
    prefixElement: document.createElement("div"),
    prefixMatches: {},
    scrollAnchor: window,
    scrollPropertyLeft: "pageXOffset",
    scrollPropertyTop: "pageYOffset",
    isTicking: false,
    calls: []
};

Каждое поле играет определённую роль.


Определение среды выполнения

Velocity автоматически определяет платформу и браузер, чтобы адаптировать поведение анимаций.

Основные флаги:

  • isMobile — указывает на мобильное устройство
  • isAndroid — определяет Android
  • isGingerbread — устаревшая версия Android (важна для совместимости)
  • isChrome, isFirefox — определяют браузер

Это необходимо для:

  • обхода багов конкретных браузеров
  • оптимизации производительности
  • выбора правильных CSS-префиксов

Работа с CSS-префиксами

prefixElement: document.createElement("div"),
prefixMatches: {}

Назначение:

  • prefixElement используется для тестирования поддержки CSS-свойств
  • prefixMatches кеширует найденные префиксы

Velocity проверяет, какие CSS-свойства поддерживаются, и автоматически подставляет нужные префиксы (-webkit-, -moz- и т.д.).

Пример внутренней логики:

if (property in element.style) {
    return property;
}

Если свойство не найдено — перебираются префиксированные варианты.


Управление прокруткой

scrollAnchor: window,
scrollPropertyLeft: "pageXOffset",
scrollPropertyTop: "pageYOffset"

Velocity поддерживает анимацию прокрутки (scroll).

Особенности:

  • scrollAnchor может быть window или DOM-элементом
  • свойства scrollPropertyLeft и scrollPropertyTop адаптируются под браузер

Это позволяет корректно работать с:

  • window.scrollTo
  • прокруткой внутри контейнеров

Основной цикл анимаций

isTicking: false,
calls: []

Это центральная часть Velocity.State.

calls — очередь анимаций

Каждый элемент массива calls содержит:

  • список анимируемых элементов
  • параметры анимации
  • время начала
  • длительность
  • easing-функцию

Структура одного вызова:

[
    tweensContainer,
    elements,
    options,
    timeStart,
    resolver
]

isTicking

Флаг, указывающий, запущен ли цикл обновления анимаций.


Механизм tick (анимационного цикла)

Velocity использует requestAnimationFrame для обновления анимаций.

Упрощённая схема:

function tick(timestamp) {
    for (var i = 0; i < Velocity.State.calls.length; i++) {
        // обработка каждой анимации
    }

    if (Velocity.State.calls.length > 0) {
        requestAnimationFrame(tick);
    } else {
        Velocity.State.isTicking = false;
    }
}

Поведение:

  • при добавлении первой анимации isTicking становится true
  • запускается цикл tick
  • цикл работает, пока есть активные анимации

Добавление анимации в очередь

При вызове:

Velocity(element, { opacity: 0.5 }, { duration: 1000 });

происходит:

  1. Создание объекта tween
  2. Формирование записи в calls
  3. Проверка isTicking
  4. Запуск tick, если он не активен

Удаление завершённых анимаций

После завершения анимации:

  • запись удаляется из calls
  • освобождаются ссылки на DOM-элементы
  • вызываются callback-функции

Это предотвращает:

  • утечки памяти
  • лишние вычисления

Оптимизация производительности

Velocity.State играет ключевую роль в оптимизации:

1. Батчинг операций

Все анимации обрабатываются в одном цикле tick, что:

  • снижает количество перерисовок
  • уменьшает нагрузку на CPU

2. Кеширование

  • CSS-префиксы сохраняются в prefixMatches
  • повторные вычисления не выполняются

3. Минимизация layout thrashing

Velocity старается:

  • группировать чтение и запись в DOM
  • избегать принудительных reflow

Взаимодействие с очередями (queue)

Velocity поддерживает очереди анимаций (fx, пользовательские).

Velocity.State.calls хранит активные анимации, а очереди управляют порядком их запуска.

Связь:

  • очередь решает, когда анимация стартует
  • State.calls — где она исполняется

Работа с Promise

Каждый вызов анимации может возвращать Promise:

Velocity(element, { opacity: 0 }).then(() => {
    console.log("Готово");
});

Внутри State.calls хранится resolver, который:

  • вызывается при завершении
  • резолвит Promise

Особенности многократных анимаций

Если один элемент участвует в нескольких анимациях:

  • создаются отдельные записи в calls
  • Velocity может объединять их при оптимизации

Потенциальные проблемы и отладка

1. Зависшие анимации

Если calls не очищается:

  • isTicking остаётся true
  • цикл продолжает работать

Причины:

  • ошибка в easing
  • некорректный callback

2. Утечки памяти

Если ссылки на элементы не удаляются:

  • DOM не освобождается

3. Конфликты с ручными изменениями DOM

Если свойства элемента изменяются вне Velocity:

  • возможны рассинхронизации

Прямой доступ к Velocity.State

Хотя это не рекомендуется, возможен доступ:

console.log(Velocity.State.calls);

Используется для:

  • отладки
  • анализа производительности
  • написания плагинов

Расширение и плагины

Плагины Velocity могут использовать Velocity.State для:

  • добавления новых типов анимаций
  • интеграции с другими системами
  • кастомного управления очередями

Взаимодействие с requestAnimationFrame

Velocity использует нативный requestAnimationFrame, но при его отсутствии:

  • применяется fallback на setTimeout

State.isTicking гарантирует:

  • отсутствие дублирующих циклов
  • контроль над частотой обновлений

Итоговая логика работы

  1. Добавление анимации → запись в calls
  2. Проверка isTicking
  3. Запуск tick
  4. Обновление значений на каждом кадре
  5. Завершение анимации → удаление из calls
  6. Остановка цикла при пустом списке

Ключевые свойства и их роль

Свойство Назначение
calls Хранение активных анимаций
isTicking Флаг работы цикла
prefixMatches Кеш CSS-префиксов
scrollAnchor Контекст прокрутки
isMobile и др. Определение среды

Глубокое понимание Velocity.State позволяет эффективно управлять анимациями, оптимизировать производительность и разрабатывать расширения, интегрирующиеся на уровне ядра Velocity.js.