14 советов по оптимизации кода JavaScript для фронт-энд разработчиков

От автора: советы и рекомендации по улучшению производительности, времени загрузки сайта и оптимизации кода JavaScript.

JavaScript стал одним из самых популярных языков программирования всех времен. По данным W3Tech, он используется почти на 96% сайтов по всему миру. Одним из ключевых фактов, которые вы должны знать о сети, является то, что вы не контролируете технические характеристики устройств, на которых пользователь будет получать доступ к вашему веб-сайту. Конечный пользователь может получить доступ к вашему веб-сайту на мощном или слабом устройстве с хорошим или плохим подключением к Интернету. Это означает, что вы должны убедиться, что ваш сайт максимально оптимизирован, чтобы вы могли удовлетворить требования любого пользователя.

Вот несколько советов, которые помогут вам получить более оптимизированный код JavaScript, который позволит повысить производительность.

Как примечание, убедитесь, что вы повторно используете компоненты JS, чтобы сохранить правильный баланс между высококачественным кодом (на создание которого нужно время) и разумными сроками доставки. Вы можете использовать популярные инструменты, такие как Bit (Github), для обмена компонентами (vanilla JS, TS, React, Vue и т. д.) из любого проекта в хаб компонентов Bit, не теряя при этом слишком много времени.

1. Удалите неиспользуемый код и функции

Чем больше кода содержится в приложении, тем больше данных необходимо передать клиенту. Кроме того, браузеру потребуется больше времени для анализа и интерпретации кода.

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

Вы можете удалить неиспользуемый код вручную или с помощью таких инструментов, как Uglify или Google Closure Compiler. Вы даже можете использовать технику, называемую встряхиванием дерева, которая удаляет неиспользуемый код из приложения. Поставщики, такие как Webpack, предоставляют эту технику. Вы можете прочитать больше о встряхивании дерева здесь. Если вы хотите удалить неиспользуемые пакеты npm, вы можете использовать команду npm prune.

2. Кешируйте, когда только это возможно

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

3. Избегайте утечек памяти

Будучи языком высокого уровня, JS заботится о нескольких низкоуровневых системах управления, таких как управление памятью. Сборка мусора — это процесс, общий для большинства языков программирования. Сборка мусора с точки зрения непрофессионала — это просто сбор и освобождение памяти, которая была выделена объектам, но которая в настоящее время не используется ни в одной части нашей программы. В таких языках программирования, как C, разработчик должен позаботиться о распределении и освобождении памяти, используя функции malloc() и dealloc().

Даже если сборка мусора выполняется в JavaScript автоматически, могут быть определенные случаи, когда она не будет идеальной. В JavaScript ES6 Map и Set были представлены со своими «более слабыми» братьями и сестрами. Этот «более слабый» аналог, известный как WeakMap и WeakSet, содержит «слабые» ссылки на объекты. Они позволяют собирать ненужные значения и предотвращать утечки памяти. Вы можете прочитать больше о WeakMaps здесь.

4. Попытайтесь выходить из циклов раньше

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

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

let arr = new Array(1000000000).fill('----');
arr[970] = 'found';
for (let i = 0; i < arr.length; i++) { if (arr[i] === 'found') { console.log("Found"); break; }
}

В приведенном ниже примере, если вы не сделали continue, когда цикл не соответствует условию, вы все равно будете запускать функцию 1000000000 раз. Мы обрабатываем элемент массива только в том случае, если он находится в четном положении. Это уменьшает выполнение цикла почти вдвое.

let arr = new Array(1000000000).fill('----');
arr[970] = 'found';
for (let i = 0; i < arr.length; i++) { if(i%2!=0){ continue; }; process(arr[i]);
}

5. Минимизируйте количество вычислений переменных

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

Давайте рассмотрим два примера, чтобы увидеть это в действии. Эти примеры взяты из блога Брета.

function findCustomerCity(name) { const texasCustomers = ['John', 'Ludwig', 'Kate']; const californiaCustomers = ['Wade', 'Lucie','Kylie']; return texasCustomers.includes(name) ? 'Texas' : californiaCustomers.includes(name) ? 'California' : 'Unknown';
};

Если мы вызываем вышеупомянутые функции несколько раз, каждый раз создается новый объект. Для каждого вызова память излишне перераспределяется на переменные texasCustometrs и californiaCustomers. Используя решение с замыканиями, мы можем создать экземпляр переменных только один раз. Давайте рассмотрим приведенный ниже пример.

function findCustomerCity() { const texasCustomers = ['John', 'Ludwig', 'Kate']; const californiaCustomers = ['Wade', 'Lucie','Kylie']; return name => texasCustomers.includes(name) ? 'Texas' : californiaCustomers.includes(name) ? 'California' : 'Unknown';
}; let cityOfCustomer = findCustomerCity();cityOfCustomer('John');//Texas
cityOfCustomer('Wade');//California
cityOfCustomer('Max');//Unknown

В приведенном выше примере с помощью замыканий внутренняя функция, которая возвращается в переменную cityOfCustomer, имеет доступ к константам внешней функции findCustomerCity(). И всякий раз, когда вызывается внутренняя функция с именем, переданным в качестве параметра, ей не нужно снова создавать экземпляры констант.

6. Минимизируйте доступ к DOM

Доступ к DOM медленный по сравнению с другими операторами JavaScript. Если вы внесете изменения в DOM, которые приведут к перерисовке макета, это может привести к замедлению работы.

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

7. Сожмите файлы

Используя такие методы сжатия, как Gzip, вы можете уменьшить размер файлов JavaScript. Эти файлы поменьше приведут к увеличению производительности сайта, так как браузер должен будет загружать меньшие ресурсы. Эти сжатия могут уменьшить размер файла до 80%. Подробнее о сжатии читайте здесь.

8. Сократите окончательный код

Некоторые люди считают, что минимизация и сжатие – это одно и то же. Вовсе нет – это разные вещи. В сжатии используются специальные алгоритмы для изменения выходного размера файла. При минимизации необходимо удалить комментарии и лишние пробелы в файлах JavaScript. Этот процесс может быть выполнен с помощью многих инструментов и пакетов, которые можно найти в Интернете. Минимизация стала стандартной практикой для оптимизации страниц и основным компонентом оптимизации интерфейса.

Минимизация может уменьшить размер файла до 60%. Вы можете прочитать больше о минимизации здесь.

9. Используйте Throttle и Debounce

Используя эти два метода, мы можем строго следить за тем, сколько раз событие должно обрабатываться кодом.
При Throttle указывается максимальное количество раз, когда функция может быть вызвана. Например, «выполнять функцию события onkeyup не чаще, чем раз в 1000 миллисекунд». Это будет означать, что если вы нажмете клавиши 20 раз в секунду, событие будет срабатывать только один раз в секунду. Это уменьшит нагрузку на код.

С другой стороны, Debounce — это то, где вы указываете минимальную продолжительность времени для повторного запуска функции с момента предыдущего выполнения той же функции. Другими словами, «выполняйте эту функцию, только если прошло 600 миллисекунд без ее вызова». Это будет означать, что функция не будет вызываться до тех пор, пока не пройдет 600 миллисекунд с момента последнего выполнения той же функции.

Вы можете реализовать собственные функции debounce и throttle или импортировать их из таких библиотек, как Lodash и Underscore.

10. Избегайте использования ключевого слова delete

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

const object = {name:"Jane Doe", age:43};
object.age = undefined;

Вы также можете использовать объект Map, так как его метод delete, согласно Брету, работает быстрее.

11. Используйте асинхронный код для предотвращения блокировки потоков

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

Но мы можем предотвратить эту ситуацию, внедрив асинхронный код. Асинхронный код был ранее написан в форме обратных вызовов, но с ES6 был введен новый стиль обработки асинхронного кода. Этот новый стиль был назван промисами. Вы можете узнать больше об обратных вызовах и промисах в официальной документации MDN.

Но подождите…

JavaScript является синхронным по умолчанию, а также однопоточным.

Как вы можете работать в одном потоке, но при этом все же выполнять асинхронный код? Здесь многие люди запутываются. Это возможно благодаря движку JavaScript, который работает под капотом браузера. Механизм JavaScript — это компьютерная программа или интерпретатор, который выполняет код JavaScript. Движок JavaScript может быть написан на самых разных языках. Например, движок V8, который поддерживает браузеры Chrome, был написан на C ++, а движок SpiderMonkey, который поддерживает браузеры Firefox, был написан на C и C ++.

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

Вы можете иногда задаться вопросом, как обстоят дела с Node.js, поскольку он не помогает браузеру работать. Фактически, тот же движок V8, который работает на Chrome, также поддерживает и Node.js.

12. Используйте разделение кода

Если у вас есть опыт работы с Google Light House, вы знакомы с метрикой, которая называется «первое значимое отображение». Это один из шести показателей, отслеживаемых в разделе «Производительность» отчета Light House.
First Contentful Paint (FCP) измеряет, сколько времени браузеру требуется для отображения первого фрагмента содержимого DOM после перехода пользователя на вашу страницу. Изображения, небелые <canvas> элементы и SVG на странице считаются содержимым DOM; ничего внутри iframe не включено.

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

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

13. Используйте async и defer

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

Это может привести к тому, что ваш громоздкий скрипт заблокирует загрузку веб-страницы. Чтобы избежать этого, JavaScript предоставляет нам две техники, известные как async и defer. Вы должны просто добавить эти атрибуты в <script> теги.

Async — это место, где вы говорите браузеру загрузить скрипт, не влияя на рендеринг. Другими словами, страница не ожидает асинхронных скриптов, содержимое обрабатывается и отображается.

Defer — это когда вы говорите браузеру загрузить скрипт после завершения рендеринга. Если вы укажете и то, и другое, async будет иметь приоритет в современных браузерах, в то время как старые браузеры, которые поддерживают, defer но не async, переходят к defer. Эти два атрибута могут помочь вам значительно сократить время загрузки страницы.

14. Используйте Web Worker для выполнения интенсивных задач процессора в фоновом режиме

Web Worker позволяют запускать скрипты в фоновых потоках. Если у вас есть очень интенсивные задачи, вы можете назначить их для Web Worker, которые будут выполнять их без вмешательства в пользовательский интерфейс. После создания Web Worker может общаться с кодом JavaScript, отправляя сообщения в обработчик событий, указанный этим кодом. Это может происходить и наоборот.

Чтобы узнать больше о Web Worker, я предлагаю вам ознакомиться с документацией MDN.

Это все. Удачного кодирования!

Автор: Mahdhi Rezvi

Источник: https://blog.bitsrc.io

Редакция: Команда webformyself.