2013-02-20 2 views
12

У меня есть время работать на некоторое время в JavaScript и обычно делают что-то вроде этого просто кэшировать значения свойств функций, объявленных внутри глубинной структуры или «пространства имен»Javascript укупорочные производительность

//global scope 
(function ($, lib) { 
    //function scope 1 
    var format = lib.format, // instead of calling lib.format all the time just call format 
    touch = lib.pointer.touch, //instead of calling lib.pointer.touch each time just touch 
    $doc = $(document), 
    log = logger.log; //not console log... 


    $doc.on('app:ready', function() { 
    //function scope 2 
    $doc.on('some:event', function (e) { 
     //function scope 3 
     //use the cached variables 
     log(format('{0} was triggered on the $doc object', e.type); 
    }); 

    $doc.on(touch, function (e) { 
     //function scope 3 
     log(format('this should be {1} and is... {0} ', e.type, touch); 
    }); 
    }); 
}(jQuery, lib)); 

Я делать это, потому что:

  • ленивыми, как я, писать сенсорный кажется более привлекательным, что написание lib.pointer.touch, даже когда мощные Иды с причудливым автозавершением могут помочь в этом, осязание короче.
  • минимизант может преобразовать эту единственную частную переменную одной переменной буквы, так оно и имело смысл для меня (я знаю, я знаю, никогда не оптимизируют слишком рано, но это, кажется безопасным, я думаю)

Весь код написанный таким образом, кажется, работает прилично на мобильных устройствах и настольных браузерах, поэтому кажется, что это безопасная практика (в «практике», каламбур предназначен). Но так как это полагается в муфтах, и внутренние функции должны создать замыкание, чтобы сохранить контекст был объявлен мне было интересно ...

  • если функция не использует переменные из внешнего контекста (свободные переменные) ... является ли контекст закрытия еще сохраненным? (или если дерево дерева падает в лес, и никто не слышит его, он все еще делает звук аварии? hehe) Я знаю, что это может варьироваться в зависимости от движка javascript, потому что ECMA ничего не говорит о том, требуется ли сохранить контекст или нет, когда переменные извне не доступны.

  • Если указанное выражение истинно ... будет ли этот блок кода более эффективным?

    //global scope 
    (function ($, lib) { 
        //function scope 1 
        var format = lib.format, 
        touch = lib.pointer.touch, 
        $doc = $(document), 
        log = console.log; 
    
        $doc.on('app:ready', function() { 
    
        (function ($doc, touch, lib, format) { 
         // since all the variables are provided as arguments in this function 
         // there is no need to save them to the [[scope]] of this function 
         // because they are local to this self invoking function now 
         $doc.on('some:event', function (e) { 
         //function scope 3 
         //use the cached variables 
         log(format('{0} was triggered on the $doc object', e.type); 
         }); 
    
         $doc.on(touch, function (e) { 
         //function scope 3 
         log(format('this should be {1} and is... {0} ', e.type, touch); 
         }); 
        }($doc, touch, lib, format));  
    
        }); 
    
    }(jQuery, lib)); 
    

Является ли это более эффективным, поскольку он передает эти переменные в себя непосредственную функцию вызывающем? будут ли затраты на создание этой новой функции какое-либо влияние на код, (отрицательный или положительный)?

  • Как я могу правильно измерить потребление памяти моей javascript-библиотеки надежным способом? У меня есть 100x маленьких модулей javascript, которые находятся внутри непосредственных функций самозапуска, в основном, чтобы избежать переполнения переменных в глобальном контексте. Таким образом, все они завернуты в модули, очень похожие на блок кода, упомянутый выше.

  • будет ли это иметь лучший эффект для кеширования переменных ближе, даже если это будет означать, что мне придется повторять объявления переменных ближе к тому, где они будут использоваться?

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

  • попытка найти неопределенную переменную из внутренних закрытий будет самой дорогой, потому что по определению переменная будет первым поиском в родительской области до тех пор, пока глобальная область действия, и не найдя ее, заставит двигатель, наконец, достичь глобальный охват. Это правда? это двигатели, оптимизирующие этот вид поиска?

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

Соответственно этому тесту ...

http://jsperf.com/closures-js

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

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

+0

У меня нет подробного ответа для вас, но я нашел это несколько дней назад. http://www.developer.nokia.com/Community/Wiki/JavaScript_Performance_Best_Practices –

+3

Это очень длинный вопрос, вы можете разделить его. – Bergi

+0

Да, возможно, слишком длинный, но все это связано с той же проблемой. Я попытаюсь сломать его или переместить примеры кода в jsfiddle, чтобы сделать его короче. спасибо –

ответ

8

Я думаю, что это преждевременная оптимизация. Вы уже знаете, что производительность не является проблемой в большинстве случаев. Даже в плотных петлях производительность не ухудшает это плохо. Пусть JavaScript-движок оптимизирует это самостоятельно, поскольку Chrome начал делать, удалив ненужные переменные из закрытий.

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

Если добавить точку останова на следующий код (в Chrome), вы увидите, что переменная world была оптимизирована из закрытия, посмотрите на узел «замкнутость» под Scope переменных http://jsfiddle.net/4J6JP/1/

enter image description here.

(function(){ 
    var hello = "hello", world="world"; 
    setTimeout(function(){ 
     debugger; 
     console.log(hello); 
    }); 
})() 

Обратите внимание, что если добавить Eval в этой внутренней функции, то все ставки выключены и закрытие не может быть оптимизирована.

+0

Спасибо, человек, так что для вас вывод, по крайней мере, не имеет смысла заботиться о выполнении закрытий, если они не станут действительно проблемой? И браузеры, похоже, делают хорошую работу, оптимизируя закрытие. Таким образом, наличие более 100 модулей внутри функций самозапуска не должно быть проблемой? –

+3

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

0

Существует стоимость исполнения, когда создаются области и контексты функций, добавив, что дополнительный размер дочернего объекта имеет стоимость, однако в этом случае он пренебрежимо мал. Итерирование только тех объектов или переменных, которые вам нужны во время работы, будет быстрее, чем преодоление лексической области и поиск там. Хорошая статья о вложенности функций здесь: http://code.tutsplus.com/tutorials/stop-nesting-functions-but-not-all-of-them--net-22315

Если я могу получить ссылку и назначить его на вар внутри лексической области я буду делать, что, однако следует быть осторожными, потому что даже после того, как родительская функция уничтожила возвращаемая функция или объект может получить доступ к этим ссылкам к «long.lib.format» с сокращенным «форматом», потому что они были объявлены в той же лексической области, если вы больше не используете ссылку, вам нужно будет уничтожить все пути в это scope. Это печально, но в это время я понимаю, что мы не можем удалить «ссылку» в этом случае «var format», поскольку тот же самый lib ссылается в другом месте, поэтому «delete format» не разрешен, однако вы можете удалить участников на объекте/lib он ссылается. Вы можете var локальный объект для хранения ссылок и удаления их, когда они больше не нужны, а затем уничтожить этот объект, не теряя других членов лексической области или области памяти.

Обновление: недавно выяснилось, что использование delete в javascript может быть медленным, скорее назначьте члену {}, когда он больше не используется.

Смежные вопросы