Уменьшите полезную нагрузку JavaScript с помощью разделения кода

Хуссейн Джирдех
Houssein Djirdeh

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

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

В окне браузера отображается приложение под названием Magic Sorter с тремя полями для ввода чисел и кнопкой сортировки.

Мера

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

  1. Для предварительного просмотра сайта нажмите «Просмотреть приложение» . Затем нажмите «Полный экран». полноэкранный .
  2. Нажмите `Control+Shift+J` (или `Command+Option+J` на Mac), чтобы открыть DevTools.
  3. Откройте вкладку Сеть .
  4. Установите флажок Отключить кэш .
  5. Перезагрузите приложение.

Сетевая панель, на которой показан пакет JavaScript размером 71,2 КБ.

71,2 КБ JavaScript-кода для сортировки нескольких чисел в простом приложении. Что это даёт?

В исходном коде ( src/index.js ) библиотека lodash импортирована и используется в этом приложении. Lodash предоставляет множество полезных функций, но здесь используется только один метод из пакета. Установка и импорт всех сторонних зависимостей, когда используется лишь малая их часть, — распространённая ошибка.

Оптимизировать

Есть несколько способов сократить размер пакета:

  1. Напишите собственный метод сортировки вместо импорта сторонней библиотеки.
  2. Используйте встроенный метод Array.prototype.sort() для числовой сортировки.
  3. Импортируйте только метод sortBy из lodash , а не всю библиотеку.
  4. Загрузите код для сортировки только тогда, когда пользователь нажмет кнопку

Варианты 1 и 2 — вполне подходящие методы уменьшения размера пакета (и, вероятно, наиболее разумные для реального приложения). Однако в этом уроке они не используются в учебных целях 😈.

Оба варианта, 3 и 4, помогают улучшить производительность этого приложения. Эти шаги будут рассмотрены в следующих нескольких разделах этой лабораторной работы. Как и в любом руководстве по программированию, всегда старайтесь писать код самостоятельно, а не копировать и вставлять.

Импортируйте только то, что вам нужно

Необходимо изменить несколько файлов, чтобы импортировать только один метод из lodash . Для начала замените эту зависимость в package.json :

"lodash": "^4.7.0",

с этим:

"lodash.sortby": "^4.7.0",

Теперь в src/index.js импортируйте этот конкретный модуль:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

И обновите порядок сортировки значений::

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Перезагрузите приложение, откройте DevTools и еще раз взгляните на панель «Сеть» .

Сетевая панель, на которой показан пакет JavaScript размером 15,2 КБ.

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

Разделение кода

Webpack — один из самых популярных сборщиков модулей с открытым исходным кодом, используемых сегодня. Он собирает все модули JavaScript (а также другие ресурсы), составляющие веб-приложение, в статические файлы, доступные для чтения браузером.

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

  • Один отвечает за код, который составляет наш первоначальный маршрут
  • Вторичный фрагмент, содержащий наш код сортировки

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

Начнем с удаления импорта верхнего уровня для метода сортировки в src/index.js :

import sortBy from "lodash.sortby";

И импортируем его в прослушиватель событий, который срабатывает при нажатии кнопки:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

Функция import() является частью предложения (в настоящее время находящегося на 3-м этапе процесса TC39) по включению возможности динамического импорта модуля. Webpack уже включил поддержку этой функции и следует тому же синтаксису, который изложен в предложении.

import() возвращает обещание, и после его завершения предоставляется выбранный модуль, который разделяется на отдельный фрагмент. После возврата модуля module.default используется для ссылки на экспорт по умолчанию, предоставляемый lodash. Это обещание связано с другим .then , который вызывает метод sortInput для сортировки трёх входных значений. В конце цепочки обещаний catch() используется для обработки случаев, когда обещание отклонено из-за ошибки.

Последнее, что нужно сделать, — это добавить метод sortInput в конец файла. Это должна быть функция, возвращающая функцию, которая принимает импортированный метод из lodash.sortBy . Вложенная функция затем сортирует три входных значения и обновляет DOM.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Монитор

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

Сетевая панель, на которой показан пакет JavaScript размером 2,7 КБ.

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

Сетевая панель, на которой показан пакет JavaScript размером 2,7 КБ, за которым следует пакет JavaScript размером 13,9 КБ.

Обратите внимание, как по-прежнему сортируются числа!

Заключение

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

Пользовательский интерфейс с отложенной загрузкой

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

Ленивая загрузка сторонних узловых модулей

Это не всегда лучший подход к отложенной загрузке сторонних зависимостей в вашем приложении, и всё зависит от того, где вы их используете. Обычно сторонние зависимости выделяются в отдельный пакет vendor , который можно кэшировать, поскольку они обновляются не так часто. Узнайте больше о том, как плагин SplitChunksPlugin может помочь вам в этом.

Ленивая загрузка с использованием JavaScript-фреймворка

Многие популярные фреймворки и библиотеки, использующие Webpack, предоставляют абстракции, которые упрощают отложенную загрузку по сравнению с использованием динамического импорта в середине вашего приложения.

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

Предварительная загрузка и предварительная выборка

По возможности используйте подсказки браузера, такие как <link rel="preload"> или <link rel="prefetch"> чтобы попытаться загрузить критически важные модули ещё быстрее. Webpack поддерживает обе подсказки благодаря использованию магических комментариев в операторах импорта. Подробнее об этом см. в руководстве « Предварительная загрузка критических фрагментов» .

Ленивая загрузка больше, чем просто код

Изображения могут составлять значительную часть приложения. Ленивая загрузка изображений, находящихся ниже сгиба или за пределами области просмотра устройства, может ускорить работу веб-сайта. Подробнее об этом читайте в руководстве Lazysizes .