2015-02-21 6 views
2

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

work(1); 
work(2); 

function work(a) { 
    // do some stuff 
    log(); 
    // do some more stuff 
    function log() { 
     console.log(a); 
    } 
} 

work инстанциируется один раз, но log экземпляр дважды?

Если log был создан при каждом запуске work, было ли вообще рекомендовано не гнездовать функции? Вместо этого напишите код следующим образом:

work(1); 
work(2); 

function work(a) { 
    // do some stuff 
    log(a); 
    // do some more stuff 
} 

function log(a) { 
    console.log(a); 
} 

Эти примеры чересчур тривиальны, и вопрос касается общего случая.

ответ

3

Работа создается один раз, но дважды создается журнал?

Да, при каждом звонке на .

Как правило, рекомендуется не устанавливать гнезда?

Почему нет? Я предполагаю, что вы намекаете на проблемы с производительностью.

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

function pad(n) { 
    return (n<10? '0' : '') + n; 
} 

очень хорошо работает в качестве помощника, где п, как ожидается, всегда быть в диапазоне от 0 до 99, но как общая функция отсутствует много особенностей (имея дело с номерами числа n, n-номеров и т. д.).

Если вы беспокоитесь о производительности, вы всегда можете использовать замыкание, поэтому помощник только инстанцирован раз:

var work = (function() { 

    function log() { 
    console.log(a); 
    } 

    return function (a) { 
    // do some stuff 
    log(); 
    // do some more stuff 
    }; 
}()); 

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

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

+0

Я понимаю, что это микро-оптимизация. Я начал задумываться об этом, потому что в моем случае эти вложенные функции определены в обработчиках запросов для http-сервера, где их экземпляры будут происходить десятки тысяч раз в секунду. Благодаря! – Tom

0

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

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

Если функция, которую вы вызываете из «работы», должна использоваться из нескольких частей вашего кода, лучше оставить их отдельными, а не вложенными в них.Это упрощает обновление кода (поскольку вы только обновляете его в одном месте).

Большинство JS-систем анализируют код только один раз (даже для вложенных функций), поэтому работа, связанная с функциями создания экземпляров, не является большой проблемой.

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

+0

«Большинство JS-систем анализируют код только один раз (даже для вложенных функций), поэтому работа, связанная с функциями создания экземпляров, не является большой проблемой». Если я правильно вас понимаю, это неправильное утверждение. Разработанные один раз, да, для создания экземпляра зависит только положение функции и повлияет на потребление ЦП и памяти. – Ben

2

Вложенные функциональные объекты создаются и добавляются к LexicalEnvironment, созданным при запуске закрывающей функции. Каждая из этих вложенных функций также будет иметь свойство [[Scope]], созданное на них. Кроме того, при запуске вложенной функции будет создан новый объект LexicalEnvironment, а будет скопирован в его свойство outer.

Когда закрывающая функция завершается, тогда вложенный объект-функция и связанная с ней память будут иметь право на сбор мусора.

Этот процесс будет повторяться для каждого вызова внешней функции.

Контрастируйте это со своей второй реализацией, где объект-функция нужно создать только один раз; также его сбор мусора.

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

0

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

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

В этом случае функции вложенности будут использовать много памяти и процессорного времени, CSO лучше всего использовать решение RobG (закрытие), где функции создаются один раз, и они просто вызываются, что приводит к меньшему использованию памяти.

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