Подтвердить что ты не робот

Производительность Javascript: While vs For Loops

На другой день во время технического интервью один из вопросов спросил: "Как вы можете оптимизировать код Javascript"?

К моему собственному удивлению, он сказал мне, что, хотя петли обычно быстрее, чем для циклов.

Это правда? И если да, то почему?

4b9b3361

Ответ 1

Вы должны были возразить, что отрицательный цикл будет еще быстрее! Смотрите: Производительность JavaScript-цикла - Почему нужно уменьшить итератор до 0 быстрее, чем приращение.

В то время как в сравнении с этими двумя источниками достаточно хорошо документировать явление скорости, запуская различные циклы в разных браузерах и сравнивая результаты в миллисекундах: https://blogs.oracle.com/greimer/entry/best_way_to_code_a и: http://www.stoimen.com/blog/2012/01/24/javascript-performance-for-vs-while/.

Концептуально, цикл for - это, в основном, пакетный цикл while, который специально ориентирован на увеличение или уменьшение (прогрессирование по логике в соответствии с некоторым порядком или некоторой длиной). Например,

for(var k=0; ++k; k< 20){ ... }

можно ускорить, сделав его отрицательным циклом while:

var k = 20;

while(--k){ ... };

и, как вы можете видеть из измерений в ссылках выше, экономия времени действительно составляет очень большие числа.

Ответ 2

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

Правильный ответ состоял бы в том, что он вообще бессмыслен беспокоиться о таких мелочах, поскольку любые усилия, которые вы вкладываете в такие Оптимизация может быть превращена в полный отход путем следующей проверки к V8 или SpiderMonkey

Поскольку Javascript определен клиентской стороной и изначально должен был быть закодирован для каждого браузера для полной совместимости с кросс-браузером (еще до того, как ECMA был даже задействован, это было хуже), разница в скорости может быть даже не логичным ответом на данный момент из-за значительная оптимизация и внедрение Javascript в браузерах и их механизмах компилятора.

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

Чтобы изложить эту тему, вам сначала нужно понять, откуда эта тема изначально исходит и компилируется против интерпретации. Позвольте взять краткую историю эволюции языков, а затем вернуться к компиляции и интерпретации. В то время как не требуется чтение, вы можете просто прочитать "Компиляция против Interpeting" для быстрого ответа, но для глубокого понимания я бы рекомендовал прочитать как компиляцию, так и интерпретацию и эволюцию программирования (показывая, как они применяются сегодня).

ПОДКЛЮЧЕНИЕ VS INTERPRETING

Компилированное кодирование языка - это метод программирования, в котором вы пишете свой код компилируемым образом, который понимает компилятор, а некоторые из наиболее известных языков сегодня - это Java, С++ и С#. Эти языки записываются с намерением, чтобы программа-компилятор переводила код в машинный код или байт-код, используемый вашей целевой машиной.

Интерпретированный код
это код, который обрабатывается J ust I n T ime (JIT) во время выполнения без компиляции сначала, он пропускает этот шаг и позволяет быстрее записывать, отлаживать, добавлять/изменять и т.д. Он также никогда не будет хранить интерпретацию script для будущего использования, она будет повторно интерпретировать script каждый раз при вызове метода. Интерпретируемый код запускается в пределах определенной и предполагаемой среды выполнения программ (для javascript обычно является браузером), который после интерпретации средой затем выводится на желаемый результат. Интерпретированные сценарии никогда не предназначены для автономного программного обеспечения и всегда хотят подключиться к допустимой среде выполнения, которая будет интерпретироваться. Вот почему script не является исполняемым. Они никогда не свяжутся напрямую с операционной системой. Если вы посмотрите на происходящие системные процессы, вы никогда не увидите обработанную script, вместо этого вы увидите обработанную программу, которая обрабатывает ваш script в среде выполнения.

Итак, пишите приветствие script в Javascript означает, что браузер интерпретирует код, определяет, что такое привет, и в то время как это происходит, браузер переводит этот код обратно на код машинного уровня, говоря, что у меня есть этот script и моя среда хочет отобразить слово hello, чтобы машина затем обработала это визуальное представление вашего script. Это постоянный процесс, из-за которого у вас есть процессоры в компьютерах и постоянное действие обработки, происходящее в системе. Ничто никогда не статично, процессы постоянно выполняются независимо от ситуации.

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

Не весь скомпилированный код создан равным
Простым способом проиллюстрировать это системы видеоигр. Playstation vs Xbox. Система Xbox построена для поддержки инфраструктуры .net для оптимизации кодирования и разработки. С# использует эту структуру в сочетании с Common Language Runtime, чтобы скомпилировать код в байт-код. Bytecode не является строгим определением скомпилированного кода, это промежуточный шаг, который помещается в процесс, который позволяет писать код быстрее и в более масштабном масштабе для программ, который затем интерпретируется, когда код выполняется во время выполнения с использованием, как вы догадались, J ust I n T ime (JIT). Разница заключается в том, что этот код интерпретируется только один раз, после компиляции программа не будет повторно интерпретировать этот код еще раз, если не будет перезапущена.

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

Playstation не использует инфраструктуру .net для своей машины. Вам нужно будет писать код на С++, С++ предназначен для компиляции и сборки для конкретной системной архитектуры. Код никогда не будет интерпретироваться и должен быть точно правильным для запуска. Вы никогда не сможете легко переместить этот тип языка, как вы могли бы на промежуточном языке. Это сделано специально для этой архитектуры машин и никогда не будет интерпретироваться иначе.

Итак, вы видите, что даже скомпилированные языки не являются окончательно завершенными версиями скомпилированного языка. Скомпилированные языки означают, в своем строгом определении, полностью скомпилированные для использования. Интерпретированные языки предназначены для интерпретации программой, но также являются наиболее переносимыми языками программирования, поскольку только требуется установленная программа, которая понимает script, но они также используют большинство ресурсов из-за постоянного интерпретации. Промежуточные языки (такие как Java и С#) являются гибридами этих 2, частично компилируясь, но также требуя использования внешних ресурсов, чтобы оставаться работоспособными. После запуска они снова скомпилируются, что является одноразовой интерпретацией во время выполнения.

Эволюция программирования

Машинный код
Самая низкая форма кодирования, этот код является строго двоичным в своем представлении (я не буду входить в тройное вычисление, поскольку он основан на теории и практическом применении для этого обсуждения). Компьютеры понимают естественные значения, вкл/выкл true/false. Это числовой код машинного уровня, который отличается от следующего уровня, ассемблерного кода.

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

Мы рассмотрели это в разделе "Не все скомпилированные коды созданы равными". Язык ассемблера является первым примером этого. Машинный код - это то, что машина читает, но язык ассемблера - это то, что человек может прочитать. По мере того, как компьютеры работают быстрее, благодаря лучшим технологическим достижениям, наши языки более низкого уровня начинают становиться более сжатыми по своей природе и не требуются для ручного внедрения. Язык ассемблера был языком кодирования высокого уровня, поскольку это был более быстрый способ кодирования машины. Это был по существу язык синтаксиса, который когда-то был собран (самая низкая форма компиляции), непосредственно преобразованная в машинный язык. Ассемблер - это компилятор, но не все компиляторы являются сборщиками.

Высокоуровневое кодирование
Языки высокого уровня кодирования - это языки, которые на один шаг выше сборки, но могут даже содержать еще более высокий уровень (это будут языки Bytecode/Intermediate). Эти языки скомпилированы из определенной структуры синтаксиса в любой требуемый машинный код, интерпретируемый байт-код или гибрид любого из предыдущих методов в сочетании со специальным компилятором, который позволяет сборку быть встроенной. Высокоуровневое кодирование, подобное предшественнику, Assembly, предназначено для снижения рабочей нагрузки разработчика и устранения любых возможных критических ошибок в избыточных задачах, таких как создание исполняемых программ. В сегодняшнем мире редко вы увидите работу разработчика в сборке ради хрустания данных в интересах одного размера. Чаще, чем разработчик может иметь ситуацию, например, в разработке игровой консоли, где им необходимо ускорить процесс. Поскольку компиляторы высокого уровня кодирования являются инструментами, которые стремятся облегчить процесс разработки, они не могут составлять 100% наиболее эффективного кода для этой системной архитектуры. В этом случае код сборки будет записан для максимального использования системных ресурсов. Но вы никогда не увидите человека, пишущего машинный код, если только вы не встретите странного.

РЕЗЮМЕ

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

Причина 1
Дни интерпретации Javascript исчезли. Все основные браузеры (да, даже Opera и Netscape) используют Javascript Engine, который был создан для компиляции script перед его внедрением. Тренировки производительности, обсуждаемые разработчиками JS с точки зрения методов без вызова, - это устаревшие методы изучения при изучении нативных функций внутри языка. Код уже скомпилирован и оптимизирован для этого, прежде чем быть частью DOM. Это не интерпретируется снова, пока эта страница обновляется, потому что эта страница является средой выполнения. Javascript действительно стал промежуточным языком, более чем интерпретированным script. Причина, по которой он никогда не будет называться промежуточным языком сценариев, заключается в том, что Javascript никогда не компилируется. Это единственная причина. Кроме того, он работает в среде браузера с минимальной версией того, что происходит с Bytecode.

Причина 2 Шансы на то, что вы пишете script или библиотеку скриптов, которые когда-либо потребуют такой большой вычислительной мощности, как настольное приложение на веб-сайте, почти ничтожны. Зачем? Потому что Javascript никогда не создавался с намерением быть всеохватывающим языком. Это создание было просто для того, чтобы обеспечить метод языкового программирования на уровне среднего уровня, который позволит обрабатывать процессы, которые не были предоставлены HTML и CSS, в то время как смягчение проблем в области разработки требует использования высокоуровневых языков кодирования, в частности Java.

CSS и JS не поддерживались в течение большей части раннего возраста веб-разработки. До 1997 года CSS не была безопасной интеграцией, и JS боролась еще дольше. Все, кроме HTML, является дополнительным языком в мире Интернета.

HTML специфичен для того, чтобы быть строительными блоками для сайта. Вы никогда не будете писать javascript для полного создания веб-сайта. В лучшем случае вы делаете манипуляции с DOM, но строите сайт.

Вы никогда не будете создавать свой сайт в JS, так как это просто не практично. CSS обрабатывает этот процесс.

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

Итак, что же мы оставили с этим? Все более просто функции и процессы. CSS3 и его будущие итерации собираются использовать все методы стилизации из Javascript. Вы видите это уже с анимациями и состояниями psuedo (зависание, активность и т.д.).

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

Ответ 3

for(var k=0; ++k; k< 20){ ... }

можно ускорить, сделав его отрицательным while loop:

var k = 20; while(--k){ ... };

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

var k = 0;
for(;;){doStuff till break}
//or we could do everything
for (var i=1, d=i*2, f=Math.pow(d, i); f < 1E9; i++, d=i*2, f=Math.pow(d,i)){console.log(f)}

В любом случае... в NodeJS v0.10.38 Я обрабатываю цикл JavaScript из 10 9 за четверть секунды, при этом для в среднем на 13% быстрее, Но это действительно не влияет на мои будущие решения, с помощью которых использовать цикл или количество, которое я выбираю для описания в цикле.

> t=Date.now();i=1E9;
> while(i){--i;b=i+1}console.log(Date.now()-t);
292
> t=Date.now();i=1E9;
> while(--i){b=i+1}console.log(Date.now()-t);
285
> t=Date.now();i=1E9;
> for(;i>0;--i){b=i+1}console.log(Date.now()-t);
265
> t=Date.now();i=1E9;
> for(;i>0;){--i;b=i+1}console.log(Date.now()-t);
246 

Ответ 4

2016 Ответ

В JavaScript быстрый обратный цикл является самым быстрым. Для циклов тривиально быстрее, чем в цикле. Будьте более ориентированы на читаемость.

Ниже приведена какая-то табличка.

Следующие теги, где протестировано:

var i,
  len = 100000,
  lenRev = len - 1;

i = 0;
while (i < len) {
    1 + 1;
    i += 1;
}

i = lenRev;
while (-1 < i) {
    1 + 1;
    i -= 1;
}

for (i = 0; i < len; i += 1) {
    1 + 1;
}

for (i = lenRev; - 1 < i; i -= 1) {
    1 + 1;
}

Ответ 5

2017 Ответ

jsperf для vs foreach в Chrome 59

Здесь вы можете увидеть, что Array.forEach стал самым быстрым в последней версии Chrome (59) на дату написания (7/31/17). Вы можете найти среднее время для других версий браузера здесь: https://jsperf.com/for-vs-foreach/66.

Это показывает, что оптимизация движка ES изменяет то, что является более эффективным в любое время.

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

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