So I'm writing this node.js application and I'm trying to make it super fast and with a low memory footprint. I've got a lot of string concatenation going on, functions like:
function f(pt) {
return pt.x + ' + ' + pt.y;
}
If I do this like 100 million times right on the inner loop of my application, does the Javascript engine allocate and have to free that string ' + '
100 million times? Would it be more performant memory-wise to rewrite this code as something like
var plus = ' + ';
function f(pt) {
return pt.x + plus + pt.y;
}
Or does the compiler just do that in the background anyway, or does it not even matter? (My code is really using much longer strings than ' + ', I just used that as an example.)
It depends.
But honestly, it might be a bit slower.
This is because it has to search for the variable plus
within the function scope, then the window object and then on the scope above to find it.
So, I believe it might be slower.
Consider the following code:
console.time('plus outside');
var plus=' x ', fn=function(pt){return pt.x + plus + pt.y};
for(var i=0; i<1e5; i++){ fn({x:5,y:6}); }
console.timeEnd('plus outside');
And this code:
console.time('plus inside');
var fn=function(pt){return pt.x + ' + ' + pt.y};
for(var i=0; i<1e5; i++){ fn({x:5,y:6}); }
console.timeEnd('plus inside');
Running both on Google Chrome v41.0.2272.89 m, plus outside
took 200ms while the inside took 175ms!
That is 25% faster!
Below, you can see a printscreen with roughly the same times:
You can test it on your computer too!
window.onload=function(){
(function(elem){
var plus=' + ',fn=function(pt){return pt.x + plus + pt.y}, start=new Date();
for(var i=0; i<1.5e7; i++){ fn({x:5,y:6}); };
var end=new Date();
elem.innerHTML=(end-start)+'ms (i:'+i+')';
})(document.getElementById('plus_outside'));
(function(elem){
var fn=function(pt){return pt.x + ' + ' + pt.y}, start=new Date();
for(var i=0; i<1.5e7; i++){ fn({x:5,y:6}); };
var end=new Date();
elem.innerHTML=(end-start)+'ms (i:'+i+')';
})(document.getElementById('plus_inside'));
(function(elem){
var fn=function(pt){return [pt.x,'+',pt.y].join(' ')}, start=new Date();
for(var i=0; i<2e5; i++){ fn({x:5,y:6}); };
var end=new Date();
elem.innerHTML=(end-start)+'ms (i:'+i+')';
})(document.getElementById('array'));
(function(elem){
var fn=function(pt){return [pt.x,' + ',pt.y].join('')}, start=new Date();
for(var i=0; i<2e5; i++){ fn({x:5,y:6}); };
var end=new Date();
elem.innerHTML=(end-start)+'ms (i:'+i+')';
})(document.getElementById('array_nojoin'));
(function(elem){
var fn=function(pt){return ([pt.x,'+',pt.y]+'').replace(',',' ')}, start=new Date();
for(var i=0; i<2e5; i++){ fn({x:5,y:6}); };
var end=new Date();
elem.innerHTML=(end-start)+'ms (i:'+i+')';
})(document.getElementById('array_replace'));
};
<font face="sans-serif">
<p>
Plus inside: <span id="plus_inside"></span><br>
fn: <code>function(pt){return pt.x + ' + ' + pt.y}</code>
</p>
<p>
Plus outside: <span id="plus_outside"></span><br>
fn: <code>function(pt){return pt.x + plus + pt.y}</code>
</p>
<p>
Array: <span id="array"></span><br>
fn: <code>function(pt){return [pt.x,'+',pt.y].join(' ')}</code>
</p>
<p>
Array (no join): <span id="array_nojoin"></span><br>
fn: <code>function(pt){return [pt.x,' + ',pt.y].join('')}</code>
</p>
<p>
Array (replace comas): <span id="array_replace"></span><br>
fn: <code>function(pt){return ([pt.x,'+',pt.y]+'').replace(',',' ')}</code>
</p>
</font>
String concatenation can be speeded up by pushing the strings onto an array. And then joining the array.
["a","b","c"].join('');
This is because join is one call and also the compiler can calculate the full length of the resulting string immediately.
This would be implementation dependent, but at least as far as V8 (Chrome) goes, no, each function call does not appear to instantiate a new ' + '
. Most likely the function body is compiled into an operation that does the concatenation in one shot.
You can see this by first defining a function (in the console):
var f = function(a, b) { return a + ' + ' + b; };
Then starting up the heap profiler and executing this:
var c = f('1', '2');
What the profiler shows is that only a single string is allocated during this time:
"1 + 2"
What this seems mean is that it's not even treating the two separate concatenation operations as separate operations. It's doing it all in one shot.
The bottom line: Micro-optimizations like this are not likely to get you far. As Ismael indicates, it might actually slow down your code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With