13 советов, как сделать код на JavaScript качественнее и быстрее
10 лет назад компания Amazon подсчитала, что 100 миллисекунд задержки стоили ей 1% выручки с продаж. Аналогичным образом в Google обнаружили, что дополнительные 500 миллисекунд на генерацию поисковых страниц сократили их трафик на 20%, на столько же урезав потенциальный доход от рекламы. Оказывается, скорость действительно решает всё. Мы публикуем перевод статьи британского разработчика Брета Кэмерона, в которой он дает 13 практических советов для увеличения скорости работы JavaScript-кода.
Меньше — лучше
Самый быстрый код — это код, который никогда не будет запущен
1. Удалите ненужные функции
Можно сразу приступить к оптимизации написанного кода, но часто наибольший прирост производительности достигается, если сделать шаг назад и спросить себя: нужен ли тот или иной сегмент на самом деле? Прежде чем перейти к оптимизации, спросите себя: должна ли ваша программа делать всё, что она делает? Необходимы ли все эти возможности, компоненты и функции? Если нет, удалите ненужное. Этот шаг невероятно важен для повышения скорости работы вашего кода, но про него легко забыть.
2. Избегайте ненужных шагов
Оценочный тест
Начав детально пересматривать код, спросите себя: каждый ли сделанный шаг необходим для успешного выполнения функции и достижения нужного результата? Например, не проходят ли данные через ненужные циклы? Следующий пример намеренно упрощен, но такое сложнее обнаружить в большой кодовой базе:
Даже в этом простом примере разница в производительности огромна: маленький работающий код быстрее большого неработающего. Хотя вышеописанную ошибку допускают немногие, в большом коде легко проглядеть лишние шаги, если нужный результат достигается. Избегайте их.
Реже — лучше
Если вы не можете удалить фрагмент кода, постарайтесь выполнять его реже
Ваш код работает в том числе за счет простого повторения операций, но тут легко переборщить и начать выполнять их чаще необходимого. Вот несколько конкретных примеров, на которые стоит обратить внимание.
3. Циклы должны завершаться как можно раньше
Оценочный тест
Обращайте внимание, есть ли необходимость выполнять каждую итерацию цикла. Например, если вы ищете конкретное значение и находите его, нет смысла в дальнейших итерациях, лучше прервать выполнение цикла оператором break:
Или, если нужно произвести операции с определенными элементами цикла, вы можете пропустить другие операции с помощью оператора continue, который останавливает выполнение операторов в текущей итерации и немедленно переходит к следующей:
Стоит также помнить, что вложенные циклы можно разрывать с помощью меток. Это позволяет привязать оператор break или continue к определенному циклу:
4. Предвычисляйте, если возможно
Оценочный тест
Возьмем следующую функцию, в нашей программе мы хотим её вызвать несколько раз:
Проблема этого кода в том, что каждый раз, когда мы вызываем функцию whichSideOfTheForce, мы создаем новый объект. При каждом вызове функции под наши массивы без необходимости выделяется память. Учитывая, что «светлые» и «темные» значения статичны, лучшим решением было бы объявить эти переменные один раз, а затем ссылаться на них при вызове whichSideOfTheForce. Мы могли бы определить наши переменные в глобальной области видимости, но тогда они могли бы изменяться за пределами нашей функции. Лучшее решение — задействовать замыкание, чтобы функция вернула своё значение:
Теперь массивы «света» и «тьмы» будут создаваться всего один раз. То же самое относится к вложенным функциям. Например:
Каждый раз, когда мы запускаем doSomething, вложенная функция создается с нуля. Замыкание поможет и здесь. Если мы возвращаем функцию, doSomethingElse остается закрытой, но создается всего один раз:
5. Минимизируйте количество операций в коде
Оценочный тест
Зачастую скорость работы кода можно повысить, если тщательно продумать порядок операций в функции. Представим себе, что у нас есть массив цен на продукты в центах и нам нужна функция для суммирования элементов и возврата результата в долларах:
Функция должна делать две вещи: конвертировать центы в доллары и суммировать элементы, но важно соблюсти порядок операций. Для конвертации в доллары мы могли бы использовать следующую функцию:
Но в этом случае мы выполняем операцию деления в каждом элементе массива. Поставив операции в обратном порядке, мы должны будем выполнить деление только один раз:
Ключевой момент — обеспечить выполнение операций в наилучшем порядке.
6. Изучите О-нотацию
Знакомство с О-нотацией — один из лучших способов понять, почему одни функции исполняются быстрее и занимают меньше места в памяти, чем другие. Например, с помощью О-нотацией можно понять, почему бинарный поиск — один из самых эффективных алгоритмов поиска, а быстрая сортировка (quicksort) — один из самых эффективных алгоритмов сортировки данных.
По сути, О-нотация помогает применять и понимать описанные в этой статье способы оптимизации. Это глубокая тема, поэтому, если вам интересно узнать больше, я рекомендую прочитать мою статью об О-нотации или статью, где я разбираю четыре варианта решения задач на собеседовании в Google в контексте затраченного времени и пространственной сложности алгоритма.
Ускоряйте исполнение
Наибольший прирост в скорости работы кода наблюдается в первых двух категориях оптимизации: делать меньше и делать реже. В этом разделе мы рассмотрим несколько способов оптимизации кода без его сокращения или уменьшения количества запусков. На самом деле, даже такая оптимизация позволит уменьшить размер кода или сделает его более удобным для компилятора, что уменьшит размер скомпилированного кода. На первый взгляд, вы меняете код, а не удаляете его, поэтому этот раздел про скорость.
7. Используйте встроенные инструменты
Оценочный тест
Для тех, кто имеет опыт работы с компиляторами и низкоуровневыми языками, этот момент может показаться очевидным. Если нужные вам инструменты уже содержатся в самом JavaScript «из коробки», используйте именно их.
Код компилятора оптимизирован с точки зрения производительности конкретных методов и типов объектов. Кроме того, базовым языком для JavaScript служит C++. Если у вас не очень специфичный случай, вероятность того, что ваша собственная реализация JavaScript превзойдет существующие методы, крайне мала.
Чтобы проверить, создадим собственную JavaScript-реализацию Array.prototype.map:
Теперь давайте создадим массив из 100 случайных чисел от 1 до 100:
Даже если мы хотим выполнить простую операцию, например, умножить каждое целое число в массиве на два, мы всё равно увидим разницу в производительности:
В моих тестах новая функция map JavaScript оказалась примерно на 65% медленнее, чем Array.prototype.map. Чтобы посмотреть исходный код реализации Array.prototype.map движка V8, кликните сюда. А чтобы провести тесты самому, кликните по ссылке на оценочный тест.
8. Используйте объекты, наиболее подходящие для конкретной задачи
Что эффективнее:
— добавлять значения в коллекцию Set или в массив с помощью push()?
— добавлять записи в коллекцию Map или в обычный объект?
Как и в предыдущих пунктах, наилучшая производительность достигается за счет выбора соответствующего объекта для решения текущей задачи. Встроенные в JavaScript объекты хорошо дополняют примитивные типы данных: числа, строки, функции, объекты и так далее. При использовании в верном контексте многие из этих менее распространенных объектов могут дать значительные преимущества в производительности.
В других статьях я писал о том, что использовать Set может быть быстрее, чем Array, а Map — чем регулярные объекты. Set и Map — это коллекции, которые используют ключи, они могу пригодиться, если вы регулярно добавляете или удаляете значения. Познакомьтесь со встроенными типами объектов и всегда используйте лучший инструмент из доступных, так вы сможете сделать код быстрее.
9. Не забудьте про память
Будучи высокоуровневым языком, JavaScript учитывает нюансы более низких уровней. Один из таких нюансов — управление памятью. JavaScript использует систему сбора «мусора» для высвобождения данных из памяти (если только явно не прописать в коде, что эти данные всё ещё нужны).
Хотя управление памятью в JavaScript выполняется автоматически, это не означает, что оно безупречно. Есть дополнительные шаги, которые можно предпринять для управления памятью и снижения вероятности утечек памяти.
Например, у функций Set и Map есть так называемые слабые вариации (WeakSet и WeakMap). Они содержат «слабые» ссылки на объекты. Они не используют тип enumerable, но они предотвращают утечку памяти, так как позволяют отправлять в «мусор» не упомянутые в коде значения.
Вы также можете лучше контролировать распределение памяти, используя объекты TypedArray, представленные в обновлении JavaScript ES2017. Например, Int8Array может принимать значения от –128 до 127 и имеет размер всего в один байт. Стоит отметить, однако, что прирост производительности при использовании объектов TypedArray может быть очень мал: сравнение обычного массива и Uint32Array показывает небольшое улучшение производительности записи, но незначительное или нулевое улучшение производительности чтения (спасибо Крису Ху за оба теста).
Поняв низкоуровневый язык программирования, вы сможете быстрее и лучше писать код на JavaScript. Об этом я пишу подробнее в своей статье «Как C++ может помочь JavaScript-разработчикам».
10. Используйте мономорфные операции, если возможно
Оценочный тест 1: мономорфные операции vs полиморфные
Оценочный тест 2: один аргумент функции vs два
Если присвоить переменной a значение 2 с помощью const, то её можно считать полиморфной (ее можно изменить). Напротив, если мы будем непосредственно использовать числовое значение 2, то его можно считать мономорфным (его значение фиксировано).
Конечно, полезно присваивать переменным значения, если нам нужно использовать их несколько раз. Если вы используете переменную только один раз, немного быстрее будет, если не устанавливать переменную вовсе. Возьмем простую функцию умножения:
Если запустить функцию multiply(2, 3), она завершится примерно на 1% быстрее, чем если запустить такой код:
Это довольно мало. Но в большой кодовой базе подобные маленькие победы складываются в большую. Таким же образом использование аргументов в функциях дает гибкость в ущерб производительности. Опять же, аргументы — это неотъемлемая часть программирования. Но если они вам не нужны, вы получите преимущество в производительности, если не будете их использовать. Еще более быстрая версия нашей функции умножения может выглядеть так:
Как я отметил ранее, улучшение производительности невелико (в моих тестах около 2%). Но если такое улучшение может быть использовано многократно в большой кодовой базе, то стоит подумать об этом. Как правило, вводить аргументы стоит тогда, когда значение динамическоe, а переменные вводятся только тогда, когда будут использоваться несколько раз.
11. Избегайте оператора delete
Оценочный тест 1: удаление свойств из объекта vs неопределенные свойства
Оценочный тест 2: оператор delete vs Map.prototype.delete
Оператор delete используется для удаления содержания из объекта. Может показаться, что он вам необходим, но если вы можете обойтись без него, то сделайте это. В движке V8 есть паттерн скрытых классов, и delete лишает вас преимуществ этого паттерна, делая объект обычным и медленным. А операции с медленными объектами — всё верно — выполняются медленнее.
В зависимости от ваших потребностей можно определить нежелательное свойство как неопределенное и, возможно, этого будет достаточно:
Я видел в интернете предположения, что было бы быстрее создать копию первоначального объекта без определенных свойств, используя следующие функции:
Однако в моих тестах функция, описанная выше, и некоторые другие работали даже медленнее, чем оператор delete. Кроме того, такие функции менее удобочитаемые, чем delete obj.a или obj.a = undefined.
В поисках альтернативы подумайте, можно ли использовать Map вместо объекта, так как Map.prototype.delete работает быстрее, чем оператор delete.
Откладывайте исполнение
Если вы не можете уменьшить код, ускорить его или реже его выполнять, есть четвертый способ оптимизации кода.
Код будет казаться более быстрым, даже если на самом деле время его выполнения не изменится. Это такая реструктуризация кода, в которой не такие критичные для всей структуры задачи не блокируют самые важные процессы.
12. Используйте асинхронный код для предотвращения блокировки потока
По умолчанию JavaScript является однопоточным языком и запускает свой код синхронно, шаг за шагом. В большинстве случаев это работает хорошо, но если у нас есть события, которые занимают много времени, не стоит блокировать или задерживать исполнение более важного кода.
Решение можно найти через асинхронный код. Некоторые встроенные инструменты работают так по умолчанию (вроде fetch() или XMLHttpRequest()), но стоит также отметить, что любую синхронную функцию можно сделать асинхронной. Если у вас длительная (синхронная) операция, например, операция над каждым из элементов в большом массиве, то такой код можно сделать асинхронным, чтобы он не блокировал выполнение другого кода. Если вы новичок в асинхронном коде JavaScript, ознакомьтесь с моей статьей «Что обещает JavaScript».
Кроме того, многие модули (например, файловая система Node.js) имеют асинхронные и синхронные варианты некоторых функций (например, fs. writeFile() и fs.writeFileSync()). В обычных условиях придерживайтесь стандартного асинхронного подхода.
13. Используйте разделение кода
Если вы используете JavaScript на стороне клиента, ваши приоритеты должны быть сосредоточены в визуальном быстродействии. Главный оценочный критерий — это First Contentful Paint (FCP), время, за которое появляется первый полезный для пользователя контент в DOM-элементах.
Разделение кода — один из лучших способов улучшить ситуацию. Вместо того, чтобы подавать ваш JavaScript-код одним большим файлом, подумайте о том, чтобы разделить его на более мелкие фрагменты. Как вы будете разбивать код, зависит от того, используете ли вы один из фреймворков (React, Angular, Vue) или обходитесь стандартными средствами самого JavaScript.
Tree shaking — связанная с описанным кодом тактика статического анализа всего кода и исключения того, что на самом деле не используется. Чтобы узнать больше, я рекомендую эту статью от Google. Не забывайте оптимизировать свой код!
Заключение
Тестирование — лучший способ проверить, удалось ли вам оптимизировать код. В этой статье я привожу примеры кода, используя https://jsperf.com, но можно проверять и меньшие сегменты коды здесь:
— http://jsben.ch
— https://jsbench.me
— Ваша собственная консоль, через функции console.time() и console.timeEnd().
Что касается проверки производительности веб-приложений, отличной отправной точкой являются разделы Chrome Dev Tools про сети и производительность. Также рекомендую расширение Lighthouse от Google.
Наконец, хочу сказать, что, хоть скорость и важна, хороший код должен быть не только быстрым. Удобочитаемость и легкость сопровождения также исключительно важны, вряд ли нужно чуть-чуть увеличивать скорость, если такое улучшение приводит к увеличению времени на поиск и исправление ошибок.
Если вы новичок, надеюсь, этот материал открыл вам глаза на некоторые способы повышения производительности кода. А если вы опытный разработчик, надеюсь, что эта статья послужила полезным дополнением к вашим знаниям.
Про оптимизацию javascript кода (часть 1)
Нижеследующее — размышления после профилирования нескольких скриптов, и поисков быстрого кода.
Все больше статей по клиентской оптимизации появляется. Но проблема в том, что практики из статей начинают применять молодые разработчики без понимания причин. Зачастую авторы статей рассказывают как они решили свою проблему.
Видел людей, которые всерьез спорят про быстрые и медленные циклы, и использование бинарных операторов для ускорения. На практике потребность в подобных манипуляциях встречается очень редко. Эти споры процветают, пишутся тесты. Правда ребята забывают, что самым узким местом клиентского JS является DOM.
При переписывании цикла на более быструю версию, кеширование переменных (для более быстрого поиска по областям видимости) скрипт можно ускорить на 5%, ну на 10%. При этом произойдет
потеря в читаемости исходного кода, его понимании.
Но ситуация с оптимизацией — палка о трех концах. Второй конец: браузерная оптимизация. Например пример двух циклов:
// 1 for (var i = 0; i
Вторая версия чуть более многословна, но быстрее первой. Третья менее многословна, но не совсем понятна слету (проход по массиву в обратном порядке не естественен для понимания).
На практике интерпретаторы сами оптимизируют код циклов, и большой разницы в скорости отработки в современном браузере профилирование не покажет, не говоря уже о пользовательских ощущениях. Какая разница, скрипт выполнится за 10мс или 9мс.
Подобные оптимизации сработают для старых браузеров. Но тут возникает вопрос целесообразности: надо ли держать такое количество непонятного кода только для оптимизации (еще не понятно необходимой ли) работы старых браузеров. Намного лучше оставить код многословным и однозначным. Пусть оптимизируют интерпретаторы.
А вот третий конец — это DOM. Обновление одного узла в DOM-e ведет за собой каскад телодвижений со стороны браузера: обновление свойств children, parentNode, nextSibling у нод, которые «цепляются» этим изменением, обновление liveCollections, триггер repaint и reflow, очистка памяти, если использован innerHTML, то еще дополнительный парсинг текста в DOM модель. На фоне такого количества действий низкоуровневые оптимизации меркнут. Слишком просто одним лишним обращением к DOM-у свести все оптимизации на нет.
Узких мест в DOM-е множество. Самые тяжелые — обновление: добавление и удаление узлов. При том время отработки одного и того же кода зависит от общей сложности DOM дерева, максимальной вложенности, количества таблиц стилей и количества правил. Это означает, что один и тот же способ оптимизации даст различный прирост, в зависимости от сложности страницы.
Браузерные производители понимают, и со своей стороны стараются оптимизировать код движков. И тут мы наблюдаем другую интересную ситуацию: разные подходы к оптимизации дают разный прирост в разных браузерах. Чем древнее браузер, тем вероятнее, что хитрые манипуляции дадут преимущество.
Снова повторяется история с циклами: не стоит усложнять исходны код, подстраивая его под браузер. Пусть этим занимаются браузеростроители.
Я к чему веду: смысла в особой оптимизации кода нет. Самый разумный подход — написать код как есть, структурировать и сделать его читаемым и понятным. И только если профилирование покажет необходимость оптимизаций, начать именно с оптимизации работы с DOM.
Цикл оптимизации в JavaScript — Сообщество разработчиков 👩💻👨💻
Если вы какое-то время писали код, возможно, у вас развился определенный уровень эмпатии к вашей машине. «Это не должно сильно работать при запуске моего кода». Не говоря уже о жесткой оптимизации алгоритма. Но да, конечно, неприятно, когда петля находится внутри другой петли.
При написании JavaScript есть много мест, где мы могли бы оптимизировать наш код, чтобы он работал быстрее.
Нравится —
- убрать горячий код из основного потока
- делать асинхронные вызовы параллельно с
Promise.all
- устранение дребезга или дросселирование определенных функций
- использовать свойства CSS, которые будут вызывать меньше циклов рендеринга
. ..и такие точки продолжаются.
Одной из самых очевидных вещей среди них является Loop. Циклы пугают. Всякий раз, когда я начинаю писать цикл, появляется «Демон перфоманса» и начинает нести чушь мне в голову. Однако следует отметить несколько хороших моментов.
Но, возможно, в большинстве случаев цикл не является причиной плохой производительности, но вы можете избежать ненужных итераций. Следовательно, люди в блоге!
На самом деле целью является любое повторение, например, цикл, рекурсия или что-то еще
В JavaScript есть много API для написания цикла. В наши дни мы в основном используем карту
, уменьшить
, фильтр
, forEach
. Мне очень приятно писать их. Потому что они применяют функциональный подход, а управление кодом также достаточно хорошее. Некоторые люди ненавидят , но уменьшают
;).
Давайте перейдем к пунктам — как мы можем лучше писать циклы?
Волшебные слова —
сломать
, продолжить
и вернуть
Давайте посмотрим на этот пример —
for(let i = 0; i < arr. length; i++){ // мы получили ответ ломать // нам не нужно идти дальше в этой итерации Продолжать // здесь тяжелые расчеты }Войти в полноэкранный режимВыйти из полноэкранного режима
Вы видите, что здесь происходит? Теперь в для каждого
, карта
, фильтр
— не останавливают. Они будут выполнять все итерации до последнего индекса
. Перерыв не работает.
Так что в таких случаях мы должны выбрать для цикла
вместо того, чтобы пытаться быть крутыми. Хотя классический цикл for
вполне удобен, вы можете использовать более привлекательный API — for of
.
для (пусть значение обр){ // мы получили ответ ломать // нам не нужно идти дальше в этой итерации Продолжать // здесь тяжелые расчеты }Войти в полноэкранный режимВыйти из полноэкранного режима
Теперь проблема в том, что если нам понадобится индекс
внутри этого цикла? В для
нет прямой поддержки индекса
.
для (пусть [index, val] of Object.entries(arr)){ }Войти в полноэкранный режимВыйти из полноэкранного режима
Если цикл находится внутри функции, и мы используем return
внутри этого цикла, вся функция вернется.
функция сделать что-то (){ for(let val of arr){ // Миссия выполнена возвращаться // здесь происходят тяжелые вычисления } }Войти в полноэкранный режимВыйти из полноэкранного режима
Это невозможно сделать в forEach
, map
или каком-либо другом функциональном методе цикла массива. Потому что у них свои возвращают
.
Вам может не понадобиться итерация
Давайте посмотрим на другой пример —
let playerInfo = [ { имя: «Месси», клуб: «Барселона» }, { имя: «Роналдо», клуб: «Ювентус» }, { имя: «Неймар», клуб: «ПСЖ» } ] // здесь мы хотим найти клуб Неймара из этого массива console. log(playerInfo.find(player => player.name === 'Неймар').club)Войти в полноэкранный режимВыйти из полноэкранного режима
Для этого нам нужно перебрать каждый элемент и посмотреть, является ли он Неймаром, а затем получить значение клуба.
Иногда подход хеширования/словаря был бы лучше. Потому что тогда нам не нужно повторять снова и снова. Просто получите доступ к значению напрямую.
const playerInfo = { Месси: «Барселона», Роналду: «Ювентус», Неймар: «ПСЖ» } console.log(playerInfo.Неймар)Войти в полноэкранный режимВыйти из полноэкранного режима
Возможно, это не лучший пример, но я уверен, что вы найдете лучший вариант использования этого подхода. 92) решение // Или же, // хешируем значение в одном цикле пусть объект = {} arr.forEach((v,i) =>
В некоторых случаях вместо цикла можно использовать математическое уравнение. Нравится — узнать суммирование явной последовательности.
пусть обр = [1, 2, 3, 4, 5] // что лучше в данном случае? // это ? let total = arr.reduce((currentVal, ReducedVal) => currentVal + ReducedVal, 0) // или это ? let n = 5 // последний элемент - arr[arr.length - 1] пусть сумма = (n * (n+1)) / 2 // еще один глупый пример // что здесь лучше? пусть обр = [2, 2, 2, 2, 2, 2] // это ? let total = eval(arr.join('+')) // eval ? В самом деле ?? // или это ? пусть сумма = 2 * длина обр.Войти в полноэкранный режимВыйти из полноэкранного режима
Используйте правильный метод массива для конкретного сценария
В JavaScript есть множество встроенных методов обработки массивов. Некоторые похожи, но у каждого своя цель. Лучше дважды подумать, прежде чем применять карту
или фильтр
для всех вариантов использования.
Например — найти
против фильтр
найти
лучше подходит, если мы ищем только один предмет. И find
останавливает итерацию после того, как найдено нужное значение. Фильтр
будет выполнять итерацию до последнего индекса, поскольку он ищет все совпадения.
Есть и другие такие же случаи.
Мемоизация
Иногда могут быть одинаковые вызовы функций с одинаковыми параметрами, в таких случаях мы можем сохранить значение при первом выполнении. Вместо повторного запуска функции мы могли бы просто использовать это сохраненное значение. Этот процесс называется мемоизацией.
Просто для общего представления — глупый пример — поищите примеры получше в Интернете.
пусть кэш = {} функция плюс(х){ // здесь могут быть сложные расчеты console.log('я здесь') // LOL вернуть х + 2 } функция memoizedPlus(a){ если (кэш [а]) { вернуть кеш[a] } еще{ кэш[а] = плюс(а) вернуть кеш[a] } } // запустите этот код в консоли и посмотрите, что произойдет console.log(memoizedPlus(5)) console. log(memoizedPlus(1)) console.log(memoizedPlus(5)) console.log(memoizedPlus(3)) console.log(memoizedPlus(3))Войти в полноэкранный режимВыйти из полноэкранного режима
У меня был план поговорить об обработке асинхронной операции внутри цикла. Может в другой статье. Так что пока это все люди! Оставайтесь в безопасности и получайте удовольствие.
производительность — Для оптимизации цикла в Javascript
спросил
Изменено 9 лет, 9 месяцев назад
Просмотрено 925 раз
Итак, я прохожу курс информатики, который использует C+ для обучения концепциям программирования. сегодня я узнал о новой концепции, которую я не был уверен, применимой к JS, в которой системные ресурсы расходуются каждый раз, когда вычисляется string. length. Это кажется незначительным, но это заставило меня задуматься об огромных массивах и о том, как они могут складываться. Посмотрите этот пример и дайте мне знать, действительно ли цикл № 2 более эффективен, чем первый, и спасибо:
var weekDay = ["Понедельник", "Вторник", "Среда"]; //для цикла №1 for(i=0; i
- javascript
- производительность
- память
- оптимизация
- цикл for
Второй подход быстрее, но ненамного. Также есть небольшая синтаксическая ошибка
for( var i = 0, n = weekDay.length; i < n; i++ ){ ... }Это довольно часто встречается в коде JavaScript. Обратите внимание на важность объявления всех ваших переменных с
var
, чтобы они не наступали на неправильную область.Вы можете увидеть этот тест производительности js здесь: http://jsperf.com/forloopiterator, который показывает, что результаты на 24% быстрее при использовании второго подхода.
Во-первых, преждевременная оптимизация - корень всех зол .
Во-вторых; Вы совершенно правы в том, что цикл №2 более эффективен.
Цикл №1 будет вычислять длину
weekDay
для на каждой итерации цикла. Это означает, что он будет вычислять длину 10 000 раз в массиве из 10 000 длин.Цикл № 2 будет вычислять длину
weekDay
и устанавливать переменнуюn
в качестве результата, поэтому мы сохраняем длину в переменной, а не пересчитываем ее для каждой итерации.Подробнее о том, почему преждевременная оптимизация — это плохо .
1
Этот вопрос задавали несколько раз... Действительно ли необходима оптимизация JavaScript для циклов?
Я нашел следующую ссылку очень полезной. В основном это зависит от версии браузера и поставщика.
В некоторых случаях, напр. IE yes #2 намного быстрее
http://jsperf.