Creating local variable counterparts of global objects if used multiple times? - javascript

I recently read, that if a global object (i.e. document) is being called multiple times then it would increase performance of the JavaScript by encapsulating this object into a local variable.
For Example, this should technically run faster..
var doc = document;
var a = doc.getElementById("id1");
var b = doc.getElementById("id2");
var c = doc.getElementById("id3");
than this..
var a = document.getElementById("id1");
var b = document.getElementById("id2");
var c = document.getElementById("id3");
Does this performance increase remain true, even in high availability/offline capable web applications and single page applications? Will memory usage grow substantially by creating local variable counterparts of highly used global objects? Why?

Even though the statement is technically correct (the name resolution would be faster if a variable is declared in a current scope so that the interpreter doesn't traverse up checking every parent scope) - it's not what you generally need to do.
That's it - the given "optimization" will not give and measurable difference but will make the code more tricky.
Also don't forget the 1st optimization rule: measure first - then optimize what is slow. Is it slow what you're trying to optimize? Nope. Then leave it as-is.
Does this performance increase remain true, even in high availability/offline capable web applications and single page applications?
It remains "true" for every piece of code written in JS.
Will memory usage grow substantially by creating local variable counterparts of highly used global objects?
Nope, it should be pretty close (you're only assigning references, the actual objects are not being copied).

Related

Does a Javascript closure retain the entire parent lexical environment or only the subset of values the closure references? [duplicate]

This question already has answers here:
About closure, LexicalEnvironment and GC
(3 answers)
Closed 3 years ago.
Consider the following example:
function makeFunction() {
let x = 3;
let s = "giant string, 100 MB in size";
return () => { console.log(x); };
}
// Are both x and s held in memory here
// or only x, because only x was referred to by the closure returned
// from makeFunction?
let made = makeFunction();
// Suppose there are no further usages of makeFunction after this point
// Let's assume there's a thorough GC run here
// Is s from makeFunction still around here, even though made doesn't use it?
made();
So if I close around just one variable from a parent lexical environment, is that variable kept around or is every sibling variable in its lexical environment also kept around?
Also, what if makeFunction was itself nested inside another outer function, would that outer lexical environment be retained even though neither makeFunction nor makeFunction's return value referred to anything in that outer lexical environment?
I'm asking for performance reasons - do closures keep a bunch of stuff around or only what they directly refer to? This impacts memory usage and also resource usage (e.g. open connections, handles, etc.).
This would be mostly in a NodeJS context, but could also apply in the browser.
V8 developer here. This is a bit complicated ;-)
The short answer is: closures only keep around what they need.
So in your example, after makeFunction has run, the string referred to by s will be eligible for garbage collection. Due to how garbage collection works, it's impossible to predict when exactly it'll be freed; "at the next garbage collection cycle". Whether makeFunction runs again doesn't matter; if it does run again, a new string will be allocated (assuming it was dynamically computed; if it's a literal in the source then it's cached). Whether made has already run or will run again doesn't matter either; what matters is that you have a variable referring to it so you could run it (again). Engines generally can't predict which functions will or won't be executed in the future.
The longer answer is that there are some footnotes. For one thing, as comments already pointed out, if your closure uses eval, then everything has to be kept around, because whatever source snippet is eval'ed could refer to any variable. (What one comment mentioned about global variables that could be referring to eval is not true though; there is a semantic difference for "global eval", a.k.a. "indirect eval": it cannot see local variables. Which is usually considered an advantage for both performance and debuggability -- but even better is to not use eval at all.)
The other footnote is that somewhat unfortunately, the tracking is not as fine-grained as it could be: each closure will keep around what any closure needs. We have tried fixing this, but as it turns out finer-grained tracking causes more memory consumption (for metadata) and CPU consumption (for doing the work) and is therefore usually not worth it for real code (although it can have massive impact on artificial tests stressing precisely this scenario). To give an example:
function makeFunction() {
let x = 3;
let s = "giant string, 100 MB in size";
let short_lived = function() { console.log(s.length); }
// short_lived(); // Call this or don't, doesn't matter.
return function long_lived() { console.log(x); };
}
let long_lived = makeFunction();
With this modified example, even though long_lived only uses x, short_lived does use s (even if it's never called!), and there is only one bucket for "local variables from makeFunction that are needed by some closure", so that bucket keeps both x and s alive. But as I said earlier: real code rarely runs into this issue, so this is usually not something you have to worry about.
Side note:
and also resource usage (e.g. open connections, handles, etc.)
As a very general statement (i.e., in any language or runtime environment, regardless of closures or whatnot), it's usually advisable not to rely on garbage collection for resource management. I recommend to free your resources manually and explicitly as soon as it is appropriate to free them.

Does declaring a variable cost an overhead?

My lead always asks me to get rid of the new variables as much as I can saying it costs an overhead. However, I'm not sure if that actually degrades the performance. If anything, making new variables improves the readability of my code. Does it actually worsen the performance?
Option 1:
var a = something1();
var b = something2();
var c = something3();
var d = something4(a, b, c);
option 2: Making it just one line of code.
var d = something4(something1(), something2(), something3());
Please note: at times, it gets complicated and the readability worsens.
In the strictest sense, yes a variable uses resources (memory or processing). But that alone doesn't mean it's bad or wasteful. Use a variable to make your code more readable and/or to store data that will be needed to be reused.
Later, when it's time to QA your work you can worry about optimization. And there is a very well-known mantra in software development that trying to optimize your code as you initially write it often leads to more problems than it solves.
But I have to say that if having something in a variable is causing your performance to suffer, you've got other problems to worry about.
If you use variable once, get rid of it. If 2+ times - declare variable.
Variable can be declared in this case only if too many executions make debug tricky. Therefore if action fits in line - it is better to use option 2
No change in performance. Just readability that also can be affected by too big amount of variables.
Both options are almost the same for the performance. With the option 2 all function calls are evaluating to a hidden internal memory space which is bound to the function parameters. This is almost an equivalent to assigning vars in option 1.

JavaScript - large for loop, should I release objects?

I have a for loop that iterates over a fair few items.
At the start of each iteration I use the same var newObj = new ...
However, I'm wondering, is this completely replacing that object each time or should I be releasing it at the end of each iteration.
If I should release - how do I do release?
For example - say x is a large number (10.000 as a high example)
for (var x = 0; x<10000; x++) {
var newObj = new someThing(x, y, z)
newObj.dance()
newObj.andDanceMore()
//Should I do some kind of release here - or am I replacing it each time
}
Thanks.
in javascript you don't have to worry about "releasing" allocated memmory,
from the great MDN docs
High-level languages (such as JS) embed a piece of software called "garbage
collector" whose job is to track memory allocation and use in order to
find when a piece of allocated memory is not needed any longer in
which case, it will automatically free it. This process is an
approximation since the general problem of knowing whether some piece
of memory is needed is undecidable (can't be solved by an algorithm).
basically the general behavior of the G.C is when an object has zero references to it - It can be garbage collected.
in the case you reffering to, each time you assigning a new value to var newObj, the G.C detect that there are 0 reffernces to it and garbage collected it - releasing it -
Short answer: no.
Slightly longer answer: There is no manual memory management in JavaScript. It is a garbage collected language. Each time the GC is launched (and you have no control over when that happens), all objects that have no references will be automatically collected, effectively freeing the memory they occupied.
Further reading: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management
Do you know what Garbage Collector is? If not, you could find very nice blogposts googling "node.js garbage collection".
In brief:
1) When you override the variable value (or local variable is being dropped with its scope), the object still remains in memory.
2) When Node.js decides to run garbage collector, your object will be wiped out from memory in the following cases:
2.1) There are no variables, containing it (actually pointing to it).
2.2) There are some variables/properties pointing to it, but the entire cluster of objects and closures with mutual links is identified as isolated.
3) You may force garbage collector run (How to request the Garbage Collector in node.js to run?), but in regular cases you do not need this.
4) Difference between let and var, mentioned in comments, does not affect your case. Yes, let is more local than var, but what? If Node.js drops let variable quitting the loop, or you override any variable (var, let, property - whatever) with new value, the result is the same.
var newObj
Will be executed only once.What the program did is that Constantly assigned to newObj in the loop, objects that are not referenced will be recycled by GC.

Uninitialized variable memory allocation

JavaScript Example:
Suppose I do this:
var i;
And never use i anywhere else in the program. Will it be allocated any memory?
Or if I use, say i=2; after some lines.... will it be allocated memory at this point, or is the memory allocated during the creation of i?
C# example:
Suppose I do this:
dynamic i;
And never use i anywhere else in the program. Will it be allocated any memory (and if it will be, when? During compilation?)?
Or if I use, say i=2; after some lines.... will it be allocated memory at this point, or is the memory allocated during the creation of i, or is it allocated during compilation?
Also, would there be any other differences regarding memory allocation in the two examples above except the differences that arise due to the fact that JavaScript is an interpreted language and C# is a compiled language?
In C#, the expression:
var i;
can't be compiled in the first place; if we consider instead:
int i; // or dynamic i;
then that can be compiled and may or may not be retained, but it depends on whether it is a field (object variable) versus a local (method variable). Fields are not removed; however, the compiler is free to remove local variables as it sees fit. Whether it chooses to do so can depend on a lot of things, but most notably: whether you are doing an optimized release build, versus a debug build. Even if a local variable is clearly both written and read, the compiler can still remove it if it chooses - of course, the value will still exist on the stack, but not in a reserved location.
When the Javascript interpreter parses var i; and then executes the containing scope, it has to store the fact somewhere that the i variable is now defined in the current scope. Futures references in this scope will access this particular variable in this scope. Though implementation details are left to the implementor, the variable i is likely added to a particular scope object and thus has to consume some memory.
It is possible that if the variable is not referenced and it is in a contained scope without the use of things like eval() that the JS engine may be able to optimize it away. Whether or not it actually thinks it can do that and actually does so would have to be discovered by testing or studying of the source code.
Individual variables like this would likely consume only very small amounts of memory. For this to be of major consequence, you would likely have to have thousands of these.

Javascript: Do complex value references affect execution speed? [duplicate]

This question already has an answer here:
javascript object access performance
(1 answer)
Closed 8 years ago.
I'm writing an animation loop and so trying to optimize for speed. This involves sacrificing a lot of readablity, but I'm wondering if at some point it becomes counter-productive. For example, I might start with something like this:
var Animation = Animations[Current_Animation];
var Sequence = Animation.Sequences[Current_Sequence];
var Action = Sequence.Actions[Current_Action];
if (Action.Repeat_Count != Action.Repeat_End) Sequence.Index--;
But when I remove the extraneous variables for optimization, it comes out with truly massive references:
if (Animations[Current_Animation].Sequences[Current_Sequence].Actions
[Animations[Current_Animation].Sequences[Current_Sequence].Index].Repeat_Count
!= Animations[Current_Animation].Sequences[Current_Sequence].Actions
[Animations[Current_Animation].Sequences[Current_Sequence].Index].Repeat_End)
Animations[Current_Animation].Sequences[Current_Sequence].Index--;
My loop is now full of such monstrosities. So I'm wondering if the interpreter having to stop and sort all of that out might actually be slower than using the placeholders. Or does it automagically know what it all means without using any extra CPU?
Thanks!
Your shorter code is more readable and faster on any JS engine I've used, not to mention if this is client side JS the download time will be shorter for less having less bytes!
However you should be using the var keyword so that all your variables aren't in the global scope. I'm sure that you have no reason for Animation, Sequence, and Action to be globals in the above code, since they are really just meant to be temporary variables, but since they are not explicitly declared as local to the current function scope, they are automatically global.
var Animation = Animations[Current_Animation];
var Sequence = Animation.Sequences[Current_Sequence];
var Action = Sequence.Actions[Current_Action];
if (Action.Repeat_Count != Action.Repeat_End) Sequence.Index--;
Per a talk given at SXSW (slide 40) this week, it is not impacting on performance in any significant way in practically any widely deployed browser.
The version which uses references (the first code sample), however, is MUCH easier to read, IMO. As noted by PaulP.R.O. it would need proper scope control via var, but it is (admittedly subjectively) better code.

Categories

Resources