var toSizeString = (function() {
var KB = 1024.0,
MB = 1024 * KB,
GB = 1024 * MB;
return function(size) {
var gbSize = size / GB,
gbMod = size % GB,
mbSize = gbMod / MB,
mbMod = gbMod % MB,
kbSize = mbMod / KB;
if (Math.floor(gbSize)) {
return gbSize.toFixed(1) + 'GB';
} else if (Math.floor(mbSize)) {
return mbSize.toFixed(1) + 'MB';
} else if (Math.floor(kbSize)) {
return kbSize.toFixed(1) + 'KB';
} else {
return size + 'B';
}
};
})();
И более быстрая функция: (обратите внимание, что она всегда должна вычислять одни и те же переменные kb / mb / gb снова и снова). Где это получить производительность?
function toSizeString (size) {
var KB = 1024.0,
MB = 1024 * KB,
GB = 1024 * MB;
var gbSize = size / GB,
gbMod = size % GB,
mbSize = gbMod / MB,
mbMod = gbMod % MB,
kbSize = mbMod / KB;
if (Math.floor(gbSize)) {
return gbSize.toFixed(1) + 'GB';
} else if (Math.floor(mbSize)) {
return mbSize.toFixed(1) + 'MB';
} else if (Math.floor(kbSize)) {
return kbSize.toFixed(1) + 'KB';
} else {
return size + 'B';
}
};
javascript
performance
томия
источник
источник
Ответы:
Все современные движки JavaScript выполняют компиляцию точно в срок. Вы не можете делать какие-либо предположения о том, что он «должен создавать снова и снова». Такого рода расчеты относительно легко оптимизировать в любом случае.
С другой стороны, закрытие константных переменных не является типичным случаем, для которого вы бы хотели использовать JIT-компиляцию. Обычно вы создаете замыкание, когда хотите иметь возможность изменять эти переменные при разных вызовах. Вы также создаете дополнительный разыменование указателя для доступа к этим переменным, например разницу между доступом к переменной-члену и локальным int в ООП.
Именно в такой ситуации люди выбрасывают строку «преждевременная оптимизация». Простые оптимизации уже сделаны компилятором.
источник
Переменные дешевы. Контексты исполнения и цепочки областей видимости дороги.
Существуют различные ответы , которые в основном сводятся к «потому затворов», и те , по сути верно, но проблема не конкретно с закрытием, это тот факт , что у вас есть функция , ссылающийся переменные в другой области. У вас возникла бы та же проблема, если бы это были глобальные переменные
window
объекта, а не локальные переменные внутри IIFE. Попробуйте и посмотрите.Итак, в вашей первой функции, когда движок видит это утверждение:
Необходимо предпринять следующие шаги:
size
в текущей области. (Нашел это.)GB
в текущей области. (Не найден.)GB
в родительской области. (Нашел это.)gbSize
.Шаг 3 значительно дороже, чем просто выделение переменной. Более того, вы делаете это пять раз , в том числе дважды для обоих
GB
иMB
. Я подозреваю, что если вы использовали псевдонимы в начале функции (напримерvar gb = GB
) и вместо этого ссылались на псевдоним, это фактически привело бы к небольшому ускорению, хотя также возможно, что некоторые движки JS уже выполняют эту оптимизацию. И, конечно же, самый эффективный способ ускорить выполнение - просто не пересекать цепочку областей действия.Имейте в виду, что JavaScript не похож на скомпилированный язык со статической типизацией, где компилятор разрешает эти переменные адреса во время компиляции. Механизм JS должен разрешать их по имени , и эти поиски происходят каждый раз во время выполнения. Таким образом, вы хотите избежать их, когда это возможно.
Переменное назначение очень дешево в JavaScript. Это может быть самая дешевая операция, хотя мне нечего подкрепить этим заявлением. Тем не менее, можно с уверенностью сказать, что почти никогда не стоит пытаться избегать создания переменных; почти любая оптимизация, которую вы пытаетесь выполнить в этой области, в конечном итоге приведет к ухудшению производительности.
источник
var a, b, c
мы можем получить к ней доступb
какscope[1]
. Все области пронумерованы, и если эта область вложена в пять областей глубиной, тоb
она полностью адресована,env[5][1]
что известно при синтаксическом анализе. В нативном коде области соответствуют сегментам стека. Замыкания являются более сложными, поскольку они должны выполнить резервное копирование и заменитьenv
*(scope->outer + variable_offset)
для доступа; каждый дополнительный уровень области действия функции стоит одна дополнительная разыменование указателя. Кажется , мы оба были правы :)Один пример предполагает закрытие, другой - нет. Реализация замыканий довольно сложна, поскольку закрытые переменные не работают как обычные переменные. Это более очевидно в низкоуровневом языке, таком как C, но я буду использовать JavaScript, чтобы проиллюстрировать это.
Замыкание состоит не только из функции, но и из всех переменных, над которыми она замкнута. Когда мы хотим вызвать эту функцию, нам также нужно предоставить все закрытые переменные. Мы можем смоделировать замыкание с помощью функции, которая получает объект в качестве первого аргумента, который представляет эти закрытые переменные:
Обратите внимание на неловкое соглашение о вызовах, которое
closure.apply(closure, ...realArgs)
требуетПоддержка встроенных объектов JavaScript позволяет опустить явный
vars
аргумент и позволяет использоватьthis
вместо него:Эти примеры эквивалентны этому коду, фактически использующему замыкания:
В этом последнем примере объект используется только для группировки двух возвращаемых функций;
this
связывание не имеет значения. Все детали создания возможных замыканий - передача скрытых данных в реальную функцию, изменение всех обращений к переменным замыкания для поиска в этих скрытых данных - решаются языком.Но вызовы замыканий включают в себя издержки передачи этих дополнительных данных, а выполнение замыканий включает издержки поиска в этих дополнительных данных, что усугубляется плохой локальностью кэша и обычно разыменованием указателя по сравнению с обычными переменными, так что неудивительно, что решение, которое не зависит от замыканий, работает лучше. Тем более, что все, что спасает ваше закрытие, - это несколько чрезвычайно дешевых арифметических операций, которые могут быть даже сложены во время анализа.
источник