Can binding out-of scope variables speed up your code? - javascript

I've been doing a lot of work in Node JS recently, and it's emphasis asynchronous modules has me relying on applying the bind function on closures to wrap asynchronous calls within loops (to preserve the values of variables at function call).
This got me thinking. When you bind variables to a function, you add passed values to that function's local scope. So in Node (or any JS code that refers to out of scope variables often), is it advantageous to bind out of scope variables (such as modules) to functions so that when used they are part of the local scope?
Example in plain JS:
var a = 1,
func1 = function(b) { console.log(a,b); },
func2 = (function(a,b) { console.log(a,b); }).bind(null, a);
//func1(2) vs func2(2)
Example in Node
var fs = require('fs'),
func1 = function(f) { fs.stat(f, function(err, stats){}); },
func2 = (function(fs, f) { fs.stat(f, function(err, stats){}); }).bind(null, fs);
//func1('file.txt') vs func2('file.txt')
In my above examples, will func1 or func2 be noticeably faster than the other (not including outside factors such as how long it takes to get file stats)?
Here's a little JSFiddle I threw together that does a quick and dirty benchmark: http://jsfiddle.net/AExvz/
Google Chrome 14.0.797.0 dev-m
Func1: 2-4ms
Func2: 30-46ms
Google Chrome 14.0.800.0 canary
Func1: 2-7ms
Func2: 35-39ms
Firefox 5.0
Func1: 0-1ms
Func2: 35-42ms
Opera 11.11 Build 2109
Func1: 21-32ms
Func2: 68-73ms
Safari 5.05 (7533.21.1)
Func1: 23-34ms
Func2: 71-78ms
Internet Explorer 9.0.8112.16421
Func1: 10-17ms
Func2: 14-17ms
Node 0.4.8 REPL
Func1: 10ms
Func2: 156ms # 10x more iterations (~15.6ms if both tested with 100000 iterations)
Note: Node's REPL test is unreliable because it must employ some sort of caching system. After a single benchmark of func1, func2 returned 0ms.
Feel free to contribute your results of a better benchmark.

Generally the effect of reducing scope lookups should be positive. However, the difference is probably rather miniscule on today's fast JS engines.
In some math-intensive code running on an older JS engine, I used to get some more perf by doing things like this:
function doSomething() {
var round = Math.round;
var floor = Math.floor;
//Do something that calls floor and round a lot
}
So basically bringing functions from outside the function to inside the function's own scope can have a positive effect, but to be sure you probably should profile the code to be sure.

As some of the users in your comments have pointed out, the bind function adds some overhead so it's not really an accurate comparison. You should test it by calling the function with arguments rather than by wrapping it with another function to bind arguments to it.
Here's a test to demonstrate (original test by cwolves):
http://jsperf.com/outer-vs-inner-references/2
Setup:
var x = 10, y = 11, z = 12, z = 13, a = 14, g = 15;
Test Case #1 (Outer reference):
(function(){
for(var i=0; i<1000; i++){
x + y + z + a + g
}
})();
Test Case #2 (Local reference):
(function(x,y,z,a,g){
for(var i=0; i<1000; i++){
x + y + z + a + g;
}
})(x,y,z,a,g);
Results:
According to this test, the second test case is much faster than the first case. Honestly, I was a bit surprised and am wondering if my own test is flawed. I knew it would be faster but figured the differences would be negligible - but apparently not?

Based on some benchmarks I completed (see question) and Jani's advice, it seems that on today's new-age browsers scope problems have been alleviated with fast engines like V8. In theory, decreasing the number of scope look-ups should increase speed, but the tests didn't support this.
For those specifically dealing with Node.JS, it seems like the only overhead you need to worry about is the first iteration of a function. When something is called repeated times in Node it seems like the V8 engine is able to cache part of the function's execution for later use. To avoid this caching a larger number of iterations was used for func2. Simple math showed that after scaling the test for func2, it was approximately 5.6ms slower than func1. Given the fluctuation you can see in most browsers, I would guess that both probably dance around values between 5ms and 15ms. I would recommend however, sticking with the func1 method as it seemed to have a slight edge and is more widely supported (I'm looking at you IE lt 9).

Related

Most efficient alternative to making functions within a loop

The function I want to create requires an access myObject.
Is it better to create the helper function inside the main function so I have access to myObject with the scope.
Or should I make the helper function outside of myFunction and pass myObject as a parameter?
EDIT: Could I get memory-leak problem with those methods?
//Method 1
var myFunction = function(myObject){
var helper = function(i){
return console.log(i,myObject[i]);
}
for(var i in myObject){
var callback = helper(i);
}
}
//Method 2
var myFunction = function(myObject){
for(var i in myObject){
var callback = helper(i,myObject);
}
}
var helper = function(i,myObject){
return console.log(i,myObject[i]);
}
I assume you're asking for performance.
Here is a jsperf to test it for you (Yup, this exists and is very neat).
So in running the tests a bunch of times I note that neither method clearly wins. It's very close and almost certainly doesn't matter. I also note that on Windows 8.1, IE 11 blows Chrome out of the water, it's not even close - like by a factor of 20. That's a neat little result but not really indicative of real world code performance and likely we're just hitting an optimized case. Within IE the in-function version is a tiny-almost-irrelevant bit faster.
You can play with the inputs somewhat (for example I just passed in a small object, maybe a big one has different results), but I'm ready to call a preliminary conclusion: Don't worry about performance here. Use whichever one makes more sense for your specific case in terms of code clarity.
Apart from performance benefit mentioned by George Mauer, I think it will be a good idea to keep it inside to keep global context clean.
Different functions can have their own helpers defined inside them with same name rather than having function1Helper, function2Helper... in the global context.

Function declaration vs expression from a performance point of view?

There's many javascript articles on the web comparing function declarations function foo (){} to function expressions var foo = function () {}. They usually mention things like hoisting, behaviour within conditionals, etc... But I don't recall any of them talking about performance. Is there any difference? Particularily in ECMA5's strict-mode (if that changes anything).
By performance I of course mean execution performance (including lookup, scope traversal, etc..) not declaration performance, although that would be a nice-to-know aswell.
Function declarations are faster in cases where there's a potential for the function expression to be evaluated multiple times. For example, in code that is called in a loop a hoisted function is only evaluated once, but an expression would be evaluated each time. Besides that, there's no meaningful difference.
Whenever you have a question about a JavaScript performance issue, I recommend checking out JSPerf. Also, Google to see if someone already made one for your question, and in this case they have:
http://jsperf.com/function-declaration-vs-function-expression/15
I executed the same tests from JSPerf in Chrome canary 45 and Firefox 37, sadly the results are opposite:
function myfunc() {
alert("yo");
}
myfunc();
Chrome: fastest, FF: much slower
var myfunc = function() {
alert("yo");
}
myfunc();
FF: fastest, Crome: much slower
So, the answer is: it depends from the browser/JS engine.

JavaScript: Overhead comparison between closure and a global function

I want to know the overhead of JavaScript closures. Suppose I have the following function:
function sum(arr, sumMethod) {
var totalSize = 0;
for (index = 0; index < arr.length; ++index) {
totalSize += sumMethod(arr[index]);
}
return totalSize;
}
If I want to know the total size of all my transfers, then I could use a global accessor function to obtain the size of a transfer. This function is passed to sum:
// Use a "global" method that is initialize only once
function getTransferSize(transfer) { return transfer.size };
...
// Obtain the total size of all transfers (called pretty often)
var totalTransferSize = sum(transfers, getTransferSize);
Another approach is to inline the accessor like this:
// Obtain the total size of all transfers (called pretty often)
var totalTransferSize = sum(transfers, function (transfer) { return transfer.size });
I would think the closure is only "compiled" once and reused over and over again, so the actual execution performance would be equal. A collegue of mine thinks that the closure is created over and over again and it hurts performance.
Can anyone explain what is the preferred method?
REMARK: I am actually using CoffeeScript, which makes closures much more readable. In CoffeeScript the code would look like this:
totalTransferSize = sum transfers, (t) -> t.size
I find this much more readable then using a global accessor function, so I would prefer to inline the accessor.
A collegue of mine thinks that the closure is created over and over again
Yes. Every time the function expression is evaluated, a new function object is instantiated.
and it hurts performance.
Unlikely. If you'd really care, measure it. The instantiation is probably much cheaper than the loop with the calls.
I would think the closure is only "compiled" once and reused over and over again
Yes, the code is compiled only once and shared by all the function instances.
so the actual execution performance would be equal.
Of the single call, yes.

How JavaScript closures are garbage collected

I've logged the following Chrome bug, which has led to many serious and non-obvious memory leaks in my code:
(These results use Chrome Dev Tools' memory profiler, which runs the GC, and then takes a heap snapshot of everything not garbaged collected.)
In the code below, the someClass instance is garbage collected (good):
var someClass = function() {};
function f() {
var some = new someClass();
return function() {};
}
window.f_ = f();
But it won't be garbage collected in this case (bad):
var someClass = function() {};
function f() {
var some = new someClass();
function unreachable() { some; }
return function() {};
}
window.f_ = f();
And the corresponding screenshot:
It seems that a closure (in this case, function() {}) keeps all objects "alive" if the object is referenced by any other closure in the same context, whether or not if that closure itself is even reachable.
My question is about garbage collection of closure in other browsers (IE 9+ and Firefox). I am quite familiar with webkit's tools, such as the JavaScript heap profiler, but I know little of other browsers' tools, so I haven't been able to test this.
In which of these three cases will IE9+ and Firefox garbage collect the someClass instance?
As far as I can tell, this is not a bug but the expected behavior.
From Mozilla's Memory management page: "As of 2012, all modern browsers ship a mark-and-sweep garbage-collector." "Limitation: objects need to be made explicitly unreachable".
In your examples where it fails some is still reachable in the closure. I tried two ways to make it unreachable and both work. Either you set some=null when you don't need it anymore, or you set window.f_ = null; and it will be gone.
Update
I have tried it in Chrome 30, FF25, Opera 12 and IE10 on Windows.
The standard doesn't say anything about garbage collection, but gives some clues of what should happen.
Section 13 Function definition, step 4: "Let closure be the result of creating a new Function object as specified in 13.2"
Section 13.2 "a Lexical Environment specified by Scope" (scope = closure)
Section 10.2 Lexical Environments:
"The outer reference of a (inner) Lexical Environment is a reference to the Lexical Environment that logically
surrounds the inner Lexical Environment.
An outer Lexical Environment may, of course, have its own outer
Lexical Environment. A Lexical Environment may serve as the outer environment for multiple inner Lexical
Environments. For example, if a Function Declaration contains two nested Function Declarations then the Lexical
Environments of each of the nested functions will have as their outer Lexical Environment the Lexical
Environment of the current execution of the surrounding function."
So, a function will have access to the environment of the parent.
So, some should be available in the closure of the returning function.
Then why isn't it always available?
It seems that Chrome and FF is smart enough to eliminate the variable in some cases, but in both Opera and IE the some variable is available in the closure (NB: to view this set a breakpoint on return null and check the debugger).
The GC could be improved to detect if some is used or not in the functions, but it will be complicated.
A bad example:
var someClass = function() {};
function f() {
var some = new someClass();
return function(code) {
console.log(eval(code));
};
}
window.f_ = f();
window.f_('some');
In example above the GC has no way of knowing if the variable is used or not (code tested and works in Chrome30, FF25, Opera 12 and IE10).
The memory is released if the reference to the object is broken by assigning another value to window.f_.
In my opinion this isn't a bug.
I tested this in IE9+ and Firefox.
function f() {
var some = [];
while(some.length < 1e6) {
some.push(some.length);
}
function g() { some; } //removing this fixes a massive memory leak
return function() {}; //or removing this
}
var a = [];
var interval = setInterval(function() {
var len = a.push(f());
if(len >= 500) {
clearInterval(interval);
}
}, 10);
Live site here.
I hoped to wind up with an array of 500 function() {}'s, using minimal memory.
Unfortunately, that was not the case. Each empty function holds on to an (forever unreachable, but not GC'ed) array of a million numbers.
Chrome eventually halts and dies, Firefox finishes the whole thing after using nearly 4GB of RAM, and IE grows asymptotically slower until it shows "Out of memory".
Removing either one of the commented lines fixes everything.
It seems that all three of these browsers (Chrome, Firefox, and IE) keep an environment record per context, not per closure. Boris hypothesizes the reason behind this decision is performance, and that seems likely, though I'm not sure how performant it can be called in light of the above experiment.
If a need a closure referencing some (granted I didn't use it here, but imagine I did), if instead of
function g() { some; }
I use
var g = (function(some) { return function() { some; }; )(some);
it will fix the memory problems by moving the closure to a different context than my other function.
This will make my life much more tedious.
P.S. Out of curiousity, I tried this in Java (using its ability to define classes inside of functions). GC works as I had originally hoped for Javascript.
Heuristics vary, but a common way to implement this sort of thing is to create an environment record for each call to f() in your case, and only store the locals of f that are actually closed over (by some closure) in that environment record. Then any closure created in the call to f keeps alive the environment record. I believe this is how Firefox implements closures, at least.
This has the benefits of fast access to closed-over variables and simplicity of implementation. It has the drawback of the observed effect, where a short-lived closure closing over some variable causes it to be kept alive by long-lived closures.
One could try creating multiple environment records for different closures, depending on what they actually close over, but that can get very complicated very quickly and can cause performance and memory problems of its own...
Maintain State between function calls
Let’s say you have function add() and you would like it to add all the values passed to it in several calls and return the sum.
like
add(5); // returns 5
add(20); // returns 25 (5+20)
add(3); // returns 28 (25 + 3)
two way you can do this first is normal define a global variable
Of course, you can use a global variable in order to hold the total. But keep in mind that this dude will eat you alive if you (ab)use globals.
now latest way using closure with out define global variable
(function(){
var addFn = function addFn(){
var total = 0;
return function(val){
total += val;
return total;
}
};
var add = addFn();
console.log(add(5));
console.log(add(20));
console.log(add(3));
}());
function Country(){
console.log("makesure country call");
return function State(){
var totalstate = 0;
if(totalstate==0){
console.log("makesure statecall");
return function(val){
totalstate += val;
console.log("hello:"+totalstate);
return totalstate;
}
}else{
console.log("hey:"+totalstate);
}
};
};
var CA=Country();
var ST=CA();
ST(5); //we have add 5 state
ST(6); //after few year we requare have add new 6 state so total now 11
ST(4); // 15
var CB=Country();
var STB=CB();
STB(5); //5
STB(8); //13
STB(3); //16
var CX=Country;
var d=Country();
console.log(CX); //store as copy of country in CA
console.log(d); //store as return in country function in d
(function(){
function addFn(){
var total = 0;
if(total==0){
return function(val){
total += val;
console.log("hello:"+total);
return total+9;
}
}else{
console.log("hey:"+total);
}
};
var add = addFn();
console.log(add);
var r= add(5); //5
console.log("r:"+r); //14
var r= add(20); //25
console.log("r:"+r); //34
var r= add(10); //35
console.log("r:"+r); //44
var addB = addFn();
var r= addB(6); //6
var r= addB(4); //10
var r= addB(19); //29
}());

Javascript closures performance

I have being working for a while in javascript and usually do something like this just to cache the value of properties of functions that are declared inside a deep structure or "namespace"
//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));
I was doing that because:
as lazy as I am, writing touch seem more appealing that writing lib.pointer.touch, even when powerful IDEs with fancy autocompletion could help on this, touch is shorter.
a minimizer could convert that single private variable to a single letter variable, so it also made sense for me (I know, I know, never optimize too soon, but this seems to be safe I guess)
All the code written that way seems to perform decently on mobile devices and desktop browsers, so It seems to be a safe practice (In "the practice", pun intended). But I since this relies in closures, and inner functions have to create a closure to save the context it was declared I was wondering...
if a function does not uses variables from the outside context (free variables)... is the closure context still saved? (or if i a tree falls in the wood and nobody is there to hear it, does it still make the crash sound? hehe) I'm aware that this could vary between javascript engines, because ECMA mention nothing about if it is required to save the context or not when variables from the outside are not accessed.
if the above expression is true... will this block of code be more efficient?
//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));
Is it more efficient because it passes those variables to self immediate invoking function? will the cost of creating that new function any impact in the code, (negative or positive)?
How I can properly measure the memory consumption of my javascript library in a reliable way? I have 100x little javascript modules all inside immediate self invoking functions mostly to avoid variables from leaking to the global context. So They all are wrapped in modules very similar to the block of code mentioned above.
will it have a better effect to cache the variables closer, even when that will mean I will have to repeat the declarations of the variables closer to where they're going to be used?
I have the feeling that looking for a variable not in the current local context, the engine will first look into the parent scope and iterate over all the variables at that level... the more variables per level, worse would probably be the performance looking for a variable.
try to find an undefined variable from the internal closures will be the most expensive, because by definition the variable will be first search on the parent scope until the global scope, and not finding it will force the engine to finally reach the global scope. Is that true? are engines optimizing this kind of lookups?
In the end... I know that I will not want to implement my code as the second example mostly because It will make the code harder to read and I'm kinda confortable with the minimized size of the final output using the first approach. My question is motivated by the curiosity and to try to understand a bit better this really nice feature of javascript.
Accordingly to this test...
http://jsperf.com/closures-js
It seems the second approach is faster. But is only evident when iterating an insane number of times... Right now my code does not do that number of iterations... but probably is consuming more memory because of my way of coding...
update: it has being pointed to me that this question is too large. I'm sorry will try to break in small parts. This question was motivated mostly by curiosity as I said, performance seems negligible even in mobile devices. Thank you for all your feedback.
I think it is premature optimization. You already know performance is not a problem in most cases. Even in tight loops, performance does not degrade that bad. Let the JavaScript engine optimize this on its own as Chrome has started doing, by removing unneeded variables from closures.
One important thing is, don't make your code harder to read with unnecessary optimization. Your example takes quite a bit more code, hampering development. In some cases, we are forced to make the code harder to read because we know a particular piece of the app is more memory/performance intensive, but only at that point should we do that.
If you add a breakpoint to the following code (in Chrome), you'll see that the world variable has been optimized out of the closure, look at the 'Closure' node under the Scope Variables http://jsfiddle.net/4J6JP/1/
.
(function(){
var hello = "hello", world="world";
setTimeout(function(){
debugger;
console.log(hello);
});
})()
Note that if you add an eval in that inner function, then all bets are off and the closure can't be optimized.

Categories

Resources