Pull to refresh

Comments 51

Ещё можно было оценить производительность конструкции with(...) { } — было бы интересно.
получилось где-то в 2 раза:
var start = new Date();
var f = a.b.c.d;
for (var i = 0; i < 1000000; i++) {
with(v){f(this)}
}
var now = new Date();
document.write("<p>Difference: " + (now - start) + "</p>");
start = new Date();
for (var i = 0; i < 1000000; i++) {
f(v);
}
now = new Date();
document.write("<p>Difference: " + (now - start) + "</p>");


IE 6: 6203 / 3250
IE 7: 7765 / 3766
Firefox 2: 10984 / 5204
Safari 3: 796 / 344
Opera 9.5: 1875 / 1078
Итак, выигрыш в 29% действительно впечатляет, но он дает всего лишь 0,7 микросекунды на итерацию, что не стоит того, чтобы это оптимизировать.

А если бы выигрыш был в 5 раз, то всё равно это было бы только около 10 мкс. Тоже не стоит оптимизировать?
зависит от числа итераций. Уже при 100 стоит задуматься, может быть, и стоит :) А если итераций несколько тысяч, то однозначно стоит.
Если уж на то пошло, то на каждой итерации цикла тратится время не только на разрешение имени в объект-функцию, но и её вызов (со всем многоэтапным созданием исполнительного контекста).
Так что разница между разрешением f и a.b.c.d далеко не 29%.

Ну и оба случая не идентичны, так как в первом случае вызов идет в контексте a.b.c, а во втором в контексте window :-D
не совсем. В первом случае window.a.b.c

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

Хорошо, что Вы вспомнили про функции. Ведь, как правило, именно в функциях, а не в глобальной области, выполняется подавляющее количество операций.
Так вот, если тестировать подобное в функциях, то результаты могут оказаться прямо противоположными, и вся эта оптимизация получит знак "минус". Вот здесь можно взглянуть на подобный тест, но с совершенно другими результатами (проявите максимум внимания - там мужчина проделал отличную работу).
Кстати, то, что Вы обращаетесь за материалом "за бугор", не используя "родной", выглядит немного странно. ;)
да, в сообщениях предложен более оптимальный вариант:
for (var i = 0, e = a.b.c.d; i < 10000; i++) {
e.e();
}
Я, конечно, в первую очередь хотел подчеркнуть, что f(v) далеко не всегда быстрее a.b.c.d(v). Но оптимальный вариант, на который Вы обратили внимание, естественно, заслуживает того. Хотя все это упирается в зависимости, которые угадать, как мне кажется, довольно сложно. Это может быть и сам движок, выполняющий js-программу, и окружение, в котором происходит вызов, и т.д. Следовательно, делать выводы об оптимизации в такой нестабильной среде надо очень осторожно.
А Вы меня перепутали с ask. :)
Мне-то все-равно, просто вдруг того человека это как-то потревожит...
Осталось только обосновать/объяснить, откуда в этом случае вылезает оптимизация.
>откуда в этом случае вылезает оптимизация.

Это Вы про dklab-оптимизацию? Или про какую?
Я для себя давно эти варианты разобрал (и даже, кажется, понял - во как!), но очень хотелось бы обсудить в деталях.
Я решил, что суть в следующем. Когда функция в качестве this value получает в свое распоряжение null (это именно тот случай, когда функция вызывается, как e(), и base object => activation object), то появляются дополнительные расходы на подстановку global вместо этого null. Под "дополнительными расходами" я подразумеваю то, что у них (во всяких monkeys) неоптимизирован алгоритм именно получения значения global, т.е. используется какая-нибудь медленная функция, типа js_ComputeGlobalThis. И это настолько "медленно", что в результате "съедается" вся оптимизация (избавление от операторов точка).
Знал бы симанку, мож чё умное и выдал бы. Звучит версия логично. Напишите в http://groups.google.com/group/netscape.… , интересно же. Я-то подозревал, что в каком-то месте работает оптимизация lookup-ов или где-то что-то кешируется (допустим, последнее значение), а в отношении неполного имени 'e' этого не происходит. Сейчас вижу, что медленнее именно вызовы и именно из-под функции... причуды движка, разрушающие js-мировоззрение. ;)
Я обратился в другую группу - comp.lang.javascript. В ней, как-будто, активность больше, соответственно и шансов больше (если поймут мой "ломаный"). Правильно сделал? Или в netscape.public.mozilla тоже написать?
В c.l.j если ответят, то не по существу, всё-таки вопрос касается внутренних алгоритмов, это ближе знатокам движка...
Это точно. Я написал, куда было сказано, и еще вот сюда написал. Там, если тема нравится, народ интересно пишет.
>Даже если dot-ов в имени много...

Да-а-а. Что ж они там "натворили" в последних версиях (в старых-то быстрее в два раза x())?
>в каком-то месте работает оптимизация lookup-ов или где-то что-то кешируется (допустим, последнее значение)

Понаблюдал еще немножко, и вот что заметил. При сохранении значения ссылки на функцию в локальной переменной не видно различий в длине цепи property accessors (т.е. f = a.b.c и f = a.b.c.d.e.f.g.h – к счастью как-будто одинаково, как и должно быть). А вот вызов метода будет занимать разное время, которое варьируется от кол-ва "точек". В IE на "точки" уходит больше времени, чем в FF – в результате "точек" пять-шесть (к примеру) уравняют время исполнения (f() и a.b.c.d.e()). В FF "точки" "быстры" – чтобы время выполнения было одинаковым, нужно для пути к методу использовать весь алфавит. Вот тут и задумаешься – есть ли оптимизация lookup-ов? Вообще, если по уму, то быть обязана, но, как мне показалось (или может так оно и есть), больше "точек" – больше времени, и это сбивает с толку (т.е. где она, оптимизация?)...
Все же для того, чтобы сделать выводы нужно еще какие-нибудь тесты придумать. Пока в голове пусто...
>в первом случае вызов идет в контексте a.b.c, а во втором в контексте window

Судя по всему, оба вызова функции происходят в глобальном контексте. Разница в том, чьим методом является анонимная функция (function(arg) { return arg; }) в момент вызова.
gro говорит о "вызове в контексте" конкретных объектов (то бишь, какое значение будет у this в зависимости от записи вызова), придирка ваша зряшная. ;) Примеры этого не учитывают, как писали 5 лет назад, так и сейчас копипастят в том же виде, без оглядки на this вообще...
>придирка ваша зряшная. ;)

Да не-е-е, не придирка вовсе! И не зряшная, как оказывается, т.к. Вы начинаете давать подсказки (это я о this). ;)
> 1 миллион итераций в 2374 миллисекунды или 2,4 микросекунды на итерацию для первого случая
2374 миллисекунды = 2.374 секунды

1с = 1000мс = 1000000мкс
http://ru.wikipedia.org/wiki/Приставки_СИ

исправьте!
что править-то? что миллион итераций на 2,4 микросекунды будет 2374 миллисекунды? :)
исправить то, что написано автором и выделено мной.
2000 миллисекунды не могут равняться 2 микросекундам.
я уже сказал, чему это равно.
возвращаясь к сказанному.
это ж надо было так построить фразу, чтобы скрыть явный смысл.

проще было бы поделить в коде на те пресловутые миллион итераций и вывести "мкс" в тексте.
95% ресурсов в JavaScript отъедает работа с DOM объектами: изменение стилей и иерархии DOM терева. Оставшиеся 5% - это непосредственные вычислительные тормоза JavaScript.

Поэтому, даже если вы получили 23% прироста в вычислительной части, то домножьте эти 23% на те 5% которые вычислительная часть занимает в сайте. Получится чуть более 1% реального прироста производительности.
гуру JavaScript'а обычно интересуются именно этим 1%. А вообще в конце авторской части статьи есть замечание как раз по этому поводу
любопытно, а я от гуру до сих пор преимущественно слышал смех над экономией на спичках ; )
примечание действительно верное
ну после ClientSide'а уже пора себя к гуру относить :) а если такая экономия не вызывает смех — так можно еще и порадоваться за свою исключительность
скромный я : )
вот разница в использовании innerHTML VS doc.createElement...node.appendChild действительно большая.
я бы сказал, что оптимизировать надо там, где профайлер показывает "плохое" время и не заморачиваться над экономией "на спичках", пока есть чем заниматься кроме этого.
Уважаемый, а где время все-таки больше в innerHTML или createElement? Сам, интуитивно использую последний вариант, но мало ли что... а до эксперемента пока руки не доходят:)
innerHTML быстрее createElement, а cloneNode самый быстрый способ если вам нужно получить множество одинаковых узлов.
Спасибо всем ответившим!:) К сожалению, пока плюсовать не могу:(
Имхо, ваш метод тестирования не оптимален. Не стоит говорить и конкретном проценте (29%) или описывайте более продробно условия теста. Сколько раз вы прогоняли тест? Сотни раз, тысячи? Ваша ОС?

Ради интереса прогнал в 4х браузерах по 10-15 раз. Результат: разброс от -10% до 45% на каждый прогон (как и следовало ожидать). Т.е. надо прогонять тест тысячи раз на _разных_ машинах и брать среднее значение.

А в общем статься полезна, спасибо ^___^
Попробуйте на цепочках jQuery потестировать.
Отлично! Хотя проблем с производительностью не возникало с цепочками и подлиннее чем в примерах, всё-равно буду иметь ввиду.
На самом деле, тут не прирост производительности на 29%.
Тут лучше с другой стороны посмореть. А с другой стороны у нас падение производительности почти на 50% относительно "оптимизированного" кода.
Проверил у себя на компьютере:
IE 6.0          : 5782 / 5094
IE 8.0 beta : 3835 / 2864
Firefox 2.0.0.1 : 1875 / 1547
Opera 9.0 : 2203 / 2047
Safari 3.0.3 : 2172 / 1906

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

напишите вот так


сильно удивитесь (-:

(function(){
var f = a.b.c.d;
for (var i = 0; i < 1000000; i++) {
f(v);
}
})();
>ха ха ... сильно удивитесь (-:

Расскажите, Вы "сильно удивлялись" на какой платформе? Ну и, собственно говоря, чему именно Вы "удивлялись" (с подробностями, если можно)?
>Sree Kotay
Интересные имя и фамилия...
Я, конечно, извиняюсь, но какой может быть байткод (и тем более JIT-компиляция) в JavaScript?
>... какой может быть байткод (и тем более JIT-компиляция) в JavaScript?

Brendan Eich:

For Mozilla 2, we will have a JIT-oriented JavaScript VM...
"JScript Classic acts like a compiled language in the sense that before any JScript Classic program runs, we fully syntax check the code, generate a full parse tree, and generate a bytecode. We then run the bytecode through a bytecode interpreter. In that sense, JScript is every bit as "compiled" as Java. The difference is that JScript does not allow you to persist or examine our proprietary bytecode. Also, the bytecode is much higher-level than the JVM bytecode — the JScript Classic bytecode language is little more than a linearization of the parse tree, whereas the JVM bytecode is clearly intended to operate on a low-level stack machine."
--Eric Lippert-- (JScript)

"Client JavaScript reads source from SCRIPT tag contents, but compiles it into an internal bytecode for faster interpretation."
--Brendan Eich-- (JavaScript)
Sign up to leave a comment.

Articles