Не инициализируйте всё подряд при jQuery.ready()

Своё первое впечатление о сайте пользователь получает при его загрузке. Никто не хочет терпеть тормозящий сайт. Все хотят мгновенной реакции на клики мышкой и быстрого взаимодействия с сайтом. Если ваш сайт использует JavaScript и jQuery, что обычное дело для многих сайтов, и возникает соблазн инициализировать всю логику (плагины, виджеты, модули, обработчики событий и др.) с целью их быстрой реакции на запросы. К сожалению, инициализация ВСЕГО ПОДРЯД во время загрузки страницы работает против быстрой загрузки страницы. Вместо инициализации всего, когда страница готова, можно подождать и инициализировать части вашего приложения по необходимости их использования.

Следующие примеры покажут два способа инициализации элемента "выбор даты". Первым способом будем "Инициализируем всё подряд" и второй пример будет использовать принцип "Инициализируем в нужный момент"

Пример разметки

Для лучшего пояснения идеи, я постараюсь показать вначале пример кода, а далее объяснить, что в нём происходит. Мы будем использовать следующий HTML для разметки нашего кода.

Я использую Twitter Bootstrap для создания презентабельного UI вида и вот почему у меня есть дополнительные классы в приведенном выше коде.

Код показывает простую форму с различными элементами ввода. В форме у нас будут различные поля данных, которые мы бы хотели инициализировать используя jQuery UI datepicker виджет.

Инициализируем всё подряд

Следующий jQuery код выглядит знакомым из многих сниппетов, которые вы должно быть видели в инете, в уроках, в своих приложениях...

Я использую маленькую moment.js библиотеку для работы с датами. Это довольно-таки удобная библиотека, которая богата различными функциями.

Разберёмся с кодом:

  1. Ждём пока документ не будет готов перед запуском остального нашего кода.
  2. Сразу после готовности DOM выбираем все input элементы страницы с классом date.
  3. jQuery будет неявно итерировать через свой внутренний набор элементов и инициализировать каждый с помощью datapicker jQuery UI виджета.

Преимущества данной техники

  • При взаимодействии пользователя с любым из input.date элементов, они будут уже установлены и поэтому будут отвечать очень быстро.

Недостатки данной техники

  • Ваш код должен ожидать готовности DOM перед тем, как он сможет выбирать элементы. Было бы неплохо, если бы вы могли использовать время между тем, когда jQuery выполняется и когда DOM готова.
  • У селектора нет никакого контекса, поэтому он ищет по всей DOM input элементы с классом date. Это будет полуоптимальный селектор, так как нет ограничения по пределам или контексту того, что ищётся.
  • Код инициализирует все элементы (скрытый цикл) нужны вам они или нет. Конечно же, виджеты готовы, когда вам они нужны, но нужен ли весь этот код на фронте сайта?
  • Куча кода исполняется, который вообще не нужен, пока не загрузилась полностью страница. Всё это влияет на скорость загрузки страницы, что является ключевым моментом для пользователей.

Инициализация в нужное время

Следующий сниппет немного отличается от предыдущего примера, но результат тот же и плюсы-минусы другие. Посмотрите внимательно и найдите отличия.


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


Я использую toastr библиотеку для вывода сообщений-индикаторов о инициализации элементов. Библиотека была создана Hans Fj?llemark и John Papa.

Так же, как мы делали в предыдущем примере, разберёмся что происходит в коде и какие плюсы-минусы такой техники.

  1. Мы немедленно устанавливаем обработчик событий в ожидание Ввода пользователя перед инициализацией ввода даты - datepicker. Это позволит коду выполняться сразу же после выполнения jQuery на странице, даже перед тем, как будет готова DOM. Нам не нужно ожидать готовности DOM, потому что мы делегируем наше событие к контексту документа - document.
  2. Мы не инициализируем все input.date элементы, только следим за событием focus. Это событие будет распространятся вверх (как пузырь) по DOM дереву, пока не дойдёт до документа - document и в этой точке jQuery определит совпадает ли сфокусированный предмет с хранимыми в нём метаданными. Это нахождение соответствия метаданным является очень быстрым, потому что сравнивается только этот "шальной" селектор с одним DOM элементом, на который попал фокус, а не всё DOM дерево.
  3. Наш продвинутый селектор ищет input.date элемент, который не имеет класса hasDatepicker. Если он совпадает, то этот DOM элемент будет инициализирован. После этого, если на элементе побывал фокус, то позже селектор не будет ему соответствовать, потому что jQuery добавила класс hasDatepicker при создании виджета для него.

Преимущества данной техники

  • Очень быстрая скорость загрузки, потому что вы только добавляете обработчик событий к документу document с некоторыми метаданными, которые будут использованы позже
  • Нет никаких селектов jQuery при готовности DOM
  • Нет скрытого цикла для инициализации элементов
  • Только элементы, которые должны использоваться, инициализируются, поэтому нет выполнения избыточного кода
  • Инициализируются элементы, на которые попал фокус, только один раз
  • Эта техника также работает для динамически добавляемых полей "ввод даты", добавляемых к DOM

Недостатки этой техники

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

Заключение

Вы постоянно хотите ограничить полную инициализацию всего. Будет полезным, если вы начнёте думать про задержку инициализации до того момента, когда это необходимо или прямо перед этим моментов. Делая так, вы можете использовать время прямо после выполнения jQuery и не ожидая готовности DOM, далее вы можете использовать это драгоценное время во время загрузки страницы. В дополнение у вас появится странный шальной jQuery селектор, очень быстрый, потому что он только проверяет один элемент, который попал в фокус, а не всё DOM дерево.

Оригинал статьи. Кто заметит неточности перевода - пишите в комментарии будем поправлять.