Какова продолжительность работы анонимной функции javascript?

Если я напишу это в глобальной области:

(function(){})();

анонимная функция, созданная, когда оператор выполняется и уничтожается сразу после выполнения инструкции?

если я напишу это в функции:

function foo()
{
    var a=1;
    (function(){})();
    a++;
}

Существует ли анонимная функция до тех пор, пока foo не вернется или не будет существовать во время выполнения этого утверждения?

Ответы

Ответ 1

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

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

Часть, которая не будет существовать все время, - это область действия и возможное создание закрытия. Объем, созданный для этой функции и закрытия, будет существовать только до тех пор, пока выполняется функция, или существует ссылка на функцию с определенной связанной областью/закрытием.

Таким образом, ссылка функции комбинации + область будет выделена в момент выполнения оператора (function(){})(); выполняется и может быть выпущен после этого утверждения. Но скомпилированная версия function(){} все еще может существовать в памяти для последующего использования.

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

Часть JIT + оптимизатора современных js-движков является сложной темой, а описание v8 можно найти здесь. Html5rocks: компиляция JavaScript:

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

Параллельно с полным компилятором V8 повторно компилирует "горячие" функции (то есть функции, которые выполняются много раз) с оптимизирующим компилятором. [...] В оптимизирующем компиляторе операции становятся спекулятивно встроенными (непосредственно размещаются там, где они вызываются). Это ускоряет выполнение (за счет объема памяти), но также обеспечивает другие оптимизации.

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

Таким образом, сразу же вызванное функциональное выражение может быть полностью оптимизировано с использованием inline.

Ответ 2

Если я напишу это в глобальной области:

(function(){})();

анонимная функция, созданная, когда оператор выполняется и уничтожается сразу после выполнения инструкции?

Как сказал t.niese, шансы на то, что двигатель полностью оптимизирует эту функцию. Поэтому допустим, что в нем есть код:

// At global scope
(function(){ console.log("Hi there"); })();

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

Теперь ответ: это зависит.

С уровня языка/спецификации весь код в блоке компиляции (грубо: сценарий) анализируется, когда блок компиляции сначала загружается. Затем эта функция создается, когда код достигает ее поэтапного выполнения, выполняемого после создания (что включает в себя создание контекста выполнения для вызова) и сразу же подходит для сбора мусора, когда это делается (вместе с контекстом выполнения) потому что ничто не ссылается на него. Но это только теория/высокоуровневая спецификация.

С точки зрения JavaScript-движка:

  • Функция анализируется до запуска любого кода. Результат этого разбора (байт-код или машинный код) будет связан с этим выражением функции. Это не дожидаясь, пока выполнение достигнет функции, это было сделано рано (в фоновом режиме на V8 [движок Google в Chrome и Node.js]).
  • Как только функция была выполнена, и ничто не может ссылаться на нее:
    • Объект функции и контекст выполнения, связанные с ее вызовом, имеют право на GC. Когда и как это происходит, зависит от механизма JavaScript.
    • Который оставляет функцию, лежащую в основе кода, либо байт-код (современные версии V8 с использованием Ignition, либо другие), либо скомпилированный машинный код (более старые версии V8 с использованием Full-codegen, другие). Может ли механизм JavaScript выкинуть, что байт-код или машинный код будут зависеть от движка. У меня нет конкретных знаний о двигателях, отбрасывающих байт-код или машинный код для функций, которые никогда не могут быть достигнуты снова. Я действительно знаю, что команда V8 тратит много времени на уменьшение отдачи памяти и бросает этот код, как низкофланговые фрукты. :-) И они специально потратили время на оптимизацию воздействия одноразового кода запуска.

Вот несколько статей в блоге V8, которые делают интересное чтение:

если я напишу это в функции:

function foo()
{
    var a=1;
    (function(){})();
    a++;
}

Существует ли анонимная функция до тех пор, пока foo не вернется или не будет существовать во время выполнения этого утверждения?

Предположим снова, что в этой функции есть console.log, и что я прав (это с моей точки зрения), что тот факт, что он полагается на записываемый глобальный (console), означает, что он не может быть просто встроен.

Ответ на высокий уровень/спецификация один и тот же: функция анализируется при загрузке сценария, создается, когда она достигнута, выполнена и имеет право на GC, когда она выполняется. Но опять же, это просто концепция высокого уровня.

На уровне двигателя, вероятно, различаются:

  • Код будет проанализирован до запуска любого кода в скрипте.
  • Вероятно, байт-код или машинный код генерируются до того, как будет запущен какой-либо код в скрипте, хотя я, кажется, что-то вспоминаю из блога V8 о разборе, но не сразу компилирую содержимое функций верхнего уровня. Я не могу найти эту статью, хотя, если бы это было не просто в моей голове.
  • Когда выполнение достигает функции, объект функции для него создается вместе с контекстом выполнения (если только двигатель не уверен, что он может оптимизировать это, не наблюдая его в коде).
  • После завершения выполнения объект функции и этот контекст выполнения имеют право на GC. (Возможно, они были в стеке, делая GC тривиальным, когда возвращается foo.)
  • Основной код, однако, хранится в памяти для повторного использования (и, если используется достаточно часто, оптимизирован).