В этой статье я попытался подготовить сводный список распространенных ошибок, которые мы, разработчики, делаем при написании кода на JavaScript, и простых способов их избежать, где это возможно.
Они полезны, независимо от того, используем ли мы библиотеку или фреймворк или просто пишем простой JS-код для нашего приложения.
1. Чем меньше, тем лучше!
Удалить ненужные шаги
Необходима ли эта функция, компонент или функция? Если нет, удалите его. Этот шаг чрезвычайно важен для повышения скорости вашего кода, но его легко упустить из виду!
Избегайте ненужных шагов
В меньшем масштабе каждый шаг, который делает функция, необходим для достижения конечного результата?
Например:
// преобразует в массив
'ненужный'.split('').slice(2).join('');
// остается строкой, по-прежнему генерирует желаемый o/p
«ненужный».slice(2);
Выйти из циклов как можно раньше
если вы ищете конкретное значение и находите это значение, следующие итерации не нужны. Вы должны прервать выполнение цикла с помощью оператора break.
если вам нужно выполнить действия только с определенными элементами в цикле, вы можете пропустить выполнение этих действий с другими элементами, используя оператор continue. Продолжить завершает выполнение операторов в текущей итерации и сразу переходит к следующей.
2. Выполняйте предварительные вычисления один раз, где это возможно
функция whichGOTHouse(name) {
const lannister = ['Серсея', 'Тайвин', 'Джейми'];
const stark = ['Нед', 'Джон'];
возврат
lannister.includes(name) ? «ланнистер»: stark.includes(name) ? «Старк» : «неизвестно»;
};
whatGOTHouse('Джейми'); // возвращает «ланнистер»
whatGOTHouse('Арья'); // возвращает «неизвестно»
Проблема с приведенным выше кодом заключается в том, что каждый раз, когда мы вызываем whichGOTHouse, мы создаем новый объект. При каждом вызове функции память излишне перераспределяется между нашими массивами Ланнистеров и Старков.
Учитывая, что значения в lannister и stark являются статическими, лучшим решением было бы объявить эти переменные один раз, а затем ссылаться на них при вызове whichGOTHouse. Хотя мы могли бы сделать это, определив наши переменные в глобальной области видимости, это позволило бы их подделывать за пределами нашей функции. Лучшим решением является использование замыкания, а это означает возврат функции.
функция whichGOTHouse(name) {
const lannister = ['Серсея', 'Тайвин', 'Джейми'];
const stark = ['Нед', 'Джон'];
return name =› lannister.includes(name) ? «ланнистер»: stark.includes(name) ? «Старк» : «неизвестно»;
};
Теперь массивы Ланнистеров и Старков будут создаваться только один раз.
3. Минимизируйте количество операций в вашем коде
Часто улучшения скорости кода можно улучшить, если тщательно продумать порядок действий в функции.
Давайте представим, что у нас есть массив цен товаров, хранящихся в центах, и нам нужна функция для суммирования товаров и возврата результата в долларах:
постоянные центы = [2305, 4150, 5725, 2544, 1900];
Функция должна делать две вещи: конвертировать центы в доллары и суммировать элементы, но важен порядок этих действий. Чтобы сначала конвертировать в доллары, мы могли бы использовать такую функцию:
функция sumCents(массив) {
вернуть ‘$’ + array.map(el =› el / 100).reduce((x, y) =› x + y);
}
Но в этом методе мы выполняем операцию деления над каждым элементом нашего массива. Поставив наши действия в обратном порядке, мы должны выполнить деление только один раз:
функция sumCents(массив) {
вернуть ‘$’ + array.reduce((x, y) =› x + y) / 100;
}
Главное — убедиться, что действия выполняются в наилучшем возможном порядке.
4. Используйте только встроенные функции вместо создания пользовательских
Как правило, если в JavaScript есть встроенный метод, используйте его. Если ваш вариант использования не является чрезвычайно специфичным, вероятность того, что ваша собственная реализация JavaScript превзойдет существующие методы, очень мала!
Вы можете просмотреть результаты тестирования сценария, в котором мы сравниваем встроенную функцию JS map и пользовательскую функцию, здесь
5. Асинхронный/синхронный
По умолчанию JavaScript является однопоточным и выполняет свой код синхронно, шаг за шагом. (Под капотом код браузера может запускать несколько потоков для захвата событий и обработчиков запуска, но — что касается написания кода JavaScript — он однопоточный).
Это хорошо работает для большей части кода JavaScript, но если у нас есть события, которые могут занять много времени, мы не хотим блокировать или задерживать выполнение более важного кода.
Решение заключается в использовании «асинхронного кода».
Это обязательно для некоторых встроенных методов, таких как fetch() или XMLHttpRequest(), но также стоит отметить, что любую синхронную функцию можно сделать асинхронной:
если у вас есть трудоемкая (синхронная) операция, например, выполнение операций над каждым элементом в большом массиве, этот код можно сделать асинхронным, чтобы он не блокировал выполнение другого кода.
Кроме того, многие модули, такие как файловая система Node.js, имеют асинхронные и синхронные варианты некоторых функций, таких как fs.writeFile() и fs.writeFileSync().
В обычных обстоятельствах придерживайтесь асинхронного метода по умолчанию.
6. Разделяй и властвуй!
Если вы используете JavaScript на стороне клиента, ваши приоритеты должны заключаться в том, чтобы визуальные элементы отображались как можно быстрее. Ключевым эталоном является «первая отрисовка содержимого», которая измеряет время от навигации до момента, когда браузер отображает первый бит контента из DOM.
Один из лучших способов улучшить это — разделение кода JavaScript. Вместо того, чтобы предоставлять свой код JavaScript в одном большом пакете, рассмотрите возможность его разделения на более мелкие фрагменты, чтобы заранее требовался минимально необходимый код JavaScript. То, как вы будете разделять код, будет зависеть от того, используете ли вы React, Angular, Vue или ванильный Javascript. И не забудьте минимизировать код для производства!
7. Используйте мономорфность везде, где это возможно!
Если мы установим let a = 2
, то переменную a можно считать полиморфной (ее можно изменить).
Напротив, если бы мы использовали 2 напрямую, это можно было бы считать мономорфным (его значение фиксировано).
Конечно, установка переменных чрезвычайно полезна, если нам нужно использовать их несколько раз. Но если вы используете переменную только один раз, будет немного быстрее вообще не устанавливать переменную. Например:
функция умножить(x, y) {
вернуть x * y;
};
Если мы запустим умножение (2, 3), это будет примерно на 1% быстрее, чем запуск:
пусть х = 2, у = 3;
умножить(х, у);
Это довольно маленькая победа. Но в большой кодовой базе много маленьких побед, подобных этой, могут складываться.
Точно так же использование аргументов в функциях обеспечивает гибкость за счет снижения производительности. Опять же, аргументы являются неотъемлемой частью программирования. Но если они вам не нужны, вы получите преимущество в производительности, не используя их. Итак, еще более быстрая версия нашей функции умножения будет выглядеть так:
функция multipleBy3(x) {
вернуть x * 3;
}
Как и выше, улучшение производительности небольшое. Но если такого рода улучшения могут быть сделаны много раз в большой кодовой базе, это стоит рассмотреть.
Как правило, вводите аргументы только тогда, когда значение должно быть динамическим, и вводите переменные только тогда, когда они будут использоваться более одного раза.
Заключение
Если вы не можете делать это меньше, делать это реже или делать это быстрее, то есть четвертая категория оптимизации, которую вы можете использовать, чтобы сделать ваш код чувствующим быстрее, даже если для его выполнения требуется точно такое же количество времени. бегать. Это включает в себя реструктуризацию вашего кода таким образом, чтобы менее важные или более сложные задачи не блокировали наиболее важные вещи.
Лучший способ убедиться, что вы действительно делаете полезную оптимизацию своего кода, — протестировать их с помощью https://jsperf.com/, но вы также можете проверить небольшие участки кода, используя:
- https://jsben.ch/
- https://jsbench.me/
- Ваша собственная консоль с использованием console.time() и console.timeEnd() .
Что касается проверки производительности целых веб-приложений, отличной отправной точкой является раздел сети и производительности Инструментов разработчика Chrome. Также рекомендуется использовать расширение Lighthouse от Google.