Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the lifetime of javascript anonymous function?

If I write this in global scope:

(function(){})();

is the anonymous function created when the statement is executed and destroyed immediately after the statement is executed?

if I write this in a function:

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

Does the anonymous function exist until foo returns, or just exist during the execution of that statement?

like image 768
William Avatar asked Oct 15 '18 07:10

William


People also ask

What is JavaScript anonymous function?

Anonymous Function is a function that does not have any name associated with it. Normally we use the function keyword before the function name to define a function in JavaScript, however, in anonymous functions in JavaScript, we use only the function keyword without the function name.

Are anonymous functions closures?

Anonymous functions, also known as closures , allow the creation of functions which have no specified name. They are most useful as the value of callable parameters, but they have many other uses. Anonymous functions are implemented using the Closure class.

Can anonymous function return JavaScript?

No, you cannot return a value from an asynchronous callback. Event callback will be called on click, but you can't assign its result.

Which is are true about anonymous functions?

An anonymous function is a function that is not stored in a program file, but is associated with a variable whose data type is function_handle . Anonymous functions can accept multiple inputs and return one output. They can contain only a single executable statement.


2 Answers

In this particular case, most engines will optimize that function entirely away, because it does not do anything.

But let's assume that function contains code and is indeed executed. In this case, the function will exist all the time, either as compiled code, as bytecode or as AST for the interpreter.

The part that won't exist all the time is the scope and the possible created closure. The scope created for that function and the closure will only exist as long as the function is executed or a reference to the function with a specific bound scope/closure exists.

So the combination function reference + scope will be allocated at the time the statement (function(){})(); is executed, and can be released after that statement. But the compiled version of function(){} might still exist in memory for later use.

For engines that do just in time compiling and optimization, a function might even exist in different compiled versions.

The JIT+optimizer part of modern js engines is a complex topic, a rough description of v8 can be found here html5rocks: JavaScript Compilation:

In V8, the Full compiler runs on all code, and starts executing code as soon as possible, quickly generating good but not great code. This compiler assumes almost nothing about types at compilation time - it expects that types of variables can and will change at runtime.

In parallel with the full compiler, V8 re-compiles "hot" functions (that is, functions that are run many times) with an optimizing compiler. [...] In the optimizing compiler, operations get speculatively inlined (directly placed where they are called). This speeds execution (at the cost of memory footprint), but also enables other optimizations.

Therefore it may be that the generated code has hardly any similarities to the original one.

So a immediately-invoked function expression might even be completely optimized away using inlining.

like image 101
t.niese Avatar answered Oct 17 '22 06:10

t.niese


If I write this in global scope:

(function(){})();

is the anonymous function created when the statement is executed and destroyed immediately after the statement is executed?

As t.niese said, odds are the engine will optimize that function away entirely. So let's assume it has some code in it:

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

The engine can't guarantee that that code won't throw an error (for instance, if you replaced console with something else), so I'm fairly sure it can't just inline that.

Now the answer is: It depends.

From a language/specification level, all code in a compilation unit (roughly: script) is parsed when the compilation unit is first loaded. Then, that function is created when the code reaches it in step-by-step execution, executed after being created (which involves creating an execution context for the call), and immediately eligible for garbage collection when done (along with the execution context) because nothing has a reference to it. But that's just theory/high-level specification.

From a JavaScript engine perspective:

  • The function is parsed before any code runs. The result of that parsing (bytecode or machine code) will be associated with that function expression. This doesn't wait for execution to reach the function, it's done early (in the background on V8 [Google's engine in Chrome and Node.js]).
  • Once the function has been executed and nothing else can refer to it:
  • The function object and the execution context associated with calling it are both eligible for GC. When and how that happens depends on the JavaScript engine.
  • Which leaves the function's underlying code, either bytecode (modern versions of V8 using Ignition, possibly others) or compiled machine code (somehow the function got used so much it got compiled for TurboFan, or older versions of V8 using Full-codegen, others). Whether the JavaScript engine can then throw away that bytecode or machine code will depend on the engine. I doubt engines throw away byte/machine code they've generated for a function if they may need it again (e.g., for a new anonymous function created by a new call to foo). If foo became unreachable, maybe foo's byte/machine code and the anonymous function's could be tossed as unnecessary. I have no idea whether engines do that. On the one hand, it seems like low-hanging fruit; on the other, it seems like something that would be so uncommon it's not worth bothering with. (Remember, here we're not talking about code attached to a function instance, but the code that has been produced from the source that gets attached to an instance when the instance is created, and may get attached to multiple instances over time.)

Here are a couple of articles on the V8 blog that make interesting reading:

  • 26 March 2018: Background compilation
  • 15 May 2017: Launching Ignition and TurboFan
  • 23 August 2016: Firing up the Ignition interpreter (some information outdated and updated by the May 2017 article)
  • Ignition (some of the Ignition information appears to be slightly out of date relative to the May 2017 article above)

if I write this in a function:

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

Does the anonymous function exist until foo returns, or just exist during the execution of that statement?

Let's assume again there's a console.log in that function, and that I'm correct (it is an assumption on my part) that the fact it relies on a writable global (console) means it can't just be inlined.

The high-level/specification answer is the same: The function is parsed when the script is loaded, created when it's reached, executed, and eligible for GC when it's done executing. But again, that's just high-level concept.

Things are probably different at the engine level:

  • The code will be parsed before any code in the script runs.
  • Bytecode or machine code is likely generated before any code in the script runs, although I seem to recall something from the V8 blog about parsing but not immediately compiling the contents of top-level functions. I can't find that article, though, if it wasn't just in my head.
  • When execution reaches the function, a function object for it is created along with an execution context (unless the engine is sure it can optimize that away without it being observable in code).
  • Once execution ends, the function object and that execution context are eligible for GC. (They may well have been on the stack, making GC trivial when foo returns.)
  • The underlying code, though, sticks around in memory in order to be used again (and if used often enough, optimized).
like image 5
T.J. Crowder Avatar answered Oct 17 '22 06:10

T.J. Crowder