Советы по повышению производительности JavaScript

Используйте локальные переменные

Когда мы объявляем глобальные переменные, они остаются в памяти на протяжении всего жизненного цикла. Однако, если мы объявляем переменные в локальном контексте, используя ключевые слова let или const, применяется блочная область видимости, и переменные удаляются из памяти после выполнения блока. Если мы сохраняем длинные текстовые строки или данные JSON в глобальных переменных, браузер может быстро исчерпать память, что приведёт к повреждению или блокировке страницы. 

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

В следующем примере мы сможем увидеть, как переменные, объявленные ключевым словом var, попадают непосредственно в тело функции (функциональная область видимости), а переменные let попадают в конкретный блок, ограниченный {} (блочная область видимости).

function foo() {
  var v1 = "Variable 1";
  let v2 = "Variable 2";
  console.log(v1, v2);
  
  {
    let v3 = "Variable 3";
    console.log(v3);
  }

console.log(v3); 
  //Uncaught ReferenceError: v3 не определён
}
foo();

На верхнем уровне переменная, объявленная ключевым словом var, создаёт свойство глобального объекта, но с переменной, объявленной ключевым словом let, этого не происходит:

//в глобальной области
var var1= "I'm in the global object";

//в глобальной области
let var2= "I'm not in the global object";

console.log(window.var1); 
//Я нахожусь в глобальном объекте

console.log(window.var2); 
//Undefined

Используйте кэш браузера

Для этого понадобится HTTP кэширование, которое помещает весь ваш JavaScript в файлы с разрешением *.js, найденные в статических местоположениях URI, или использует сервисные воркеры. Браузер утилизирует локально закэшированную копию ваших скриптов или данных при следующих выполнениях. 

Кэшируйте DOM

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

Избегайте рекурсивных вызовов

Стек вызовов является ограниченным ресурсом, и если мы вызовем функции рекурсивно и не будем осторожны, то легко получим переполнение стека. Один из способов минимизировать это — использовать оптимизацию вызовов ES6 Tail. При оптимизации вызовов Tail, если последнее выражение в функции является вызовом другой функции, движок оптимизирует стек вызовов для предотвращения его переполнения. 

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

Используйте XMLHttpRequest, fetch или подобные

Ajax запрос помогает снизить объём содержимого, поступающего от сервера, и избежать влияния на производительность пересоздания среды выполнения между загрузками страницы. 

Реализовывайте делегирование событий 

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

Минимизируйте и объединяйте ваш код в модули 

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

Например, если вы пропустите следующий код через онлайн-минимизатор, к примеру, javascript-minifier, вы получите следующее:

var myValues= [];
for (var i = 0; i < 5; i++) {
  myValues[i] = i + 10;
  console.log("You have" +  i  +"items");
}

//Минимизированный код
for(var myValues=[],i=0;i<5;i++)myValues[i]=i+10,console.log("You have"+i+"items");

А вот разница в 187 Кб между исходной и уменьшенной версией библиотеки Jquery:

Исходный и уменьшенный файлы Jquery

Если вы используете инструмент статического объединения файлов, такой как WebPack, рекомендую включить минимизатор в его поток. 

Используйте функцию Await верхнего уровня

С Await верхнего уровня ECMAScript модули могут ожидать ресурсы или выбирать время их загрузки, помогая увеличивать общую производительность приложения. Больше об этой новой функции можно прочитать в моей статье “Как работает новая функция await верхнего уровня.”

Будьте осторожны с добавлением лишних зависимостей

С такими менеджерами пакетов, как npm или yarn, мы легко можем скачивать и использовать тысячи общедоступных пакетов. Но зачастую мы подключаем ненужные библиотеки или библиотеки, содержащие ненужные функции. Чтобы это исправить, проанализируйте пакет перед установкой для обнаружения неиспользуемого кода, а затем удалите неиспользуемые и ненужные библиотеки. 

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

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

Используйте инструмент объединения файлов JavaSript

Объединение в JavaScript — это процедура группировки отдельных файлов для снижения числа HTTP запросов, необходимых для загрузки страницы, и сокращения времени загрузки запроса. Объединение обычно используется в современной “модульной” разработке. Существуют инструменты, такие как Webpack, помогающие автоматизировать объединение скриптов. 

Используйте инструменты для отладки

Существует множество инструментов, помогающих обнаружить проблемы на веб-страницах. В Chrome можно использовать функцию в основном меню, чтобы увидеть память, сеть и производительность в отдельных вкладках. Кроме того, в Chrome есть вкладка Audits, помогающая обнаружить и исправить типичные проблемы, влияющие на производительность, доступность и удобство сайтов. Online-инструменты, например PageSpeed Insights, помогают в анализе сайтов. 

Инструменты разработчика Chrome

Используя менеджер пакетов вроде Node, вы можете воспользоваться командой npm audit для выявления проблем с пакетами или NodeSource Platform для проверки производительности приложений. 

Заключение

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

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Kesk Noren: Tips for improving JavaScript performance that your users will love

Предыдущая статьяAndroid 12: радикально новый дизайн от Google
Следующая статьяПрограммирование на квантовых компьютерах: какой язык учить?