我应该静态地为内存性能分配Javascript字符串吗?

时间:2015-03-12 09:05:32

标签: javascript node.js performance

所以我正在编写这个node.js应用程序,我正试图让它超级快,内存占用少。我有很多字符串连接,函数如下:

function f(pt) { 
    return pt.x + ' + ' + pt.y; 
}

如果我在我的应用程序的内循环上这样做了1亿次,Javascript引擎是否分配并且必须释放该字符串' + ' 1亿次?将此代码重写为

之类的代码是否会更加高效
var plus = ' + ';
function f(pt) { 
    return pt.x + plus + pt.y; 
}

或者编译器是否只是在后台执行此操作,或者甚至不重要? (我的代码实际上使用了比'+'更长的字符串,我只是用它作为例子。)

3 个答案:

答案 0 :(得分:5)

取决于。

但说实话,它可能会慢一点 这是因为它必须在函数范围内搜索变量plus,然后在窗口对象上搜索,然后在上面的范围内查找它。

所以,我相信它可能会变慢。

请考虑以下代码:

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');

这段代码:

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');

在谷歌浏览器v41.0.2272.89米上运行,plus outside耗时200毫秒,内部耗时 175 毫秒! 这快了25%!

下面,您可以看到大致相同的版画屏幕:

chrome console

您也可以在计算机上测试它!

&#13;
&#13;
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'));
  

};
&#13;
<font face="sans-serif">
<p>
  Plus inside: <span id="plus_inside"></span><br>
  &nbsp;&nbsp;fn: <code>function(pt){return pt.x + ' + ' + pt.y}</code>
</p>

<p>
  Plus outside: <span id="plus_outside"></span><br>
  &nbsp;&nbsp;fn: <code>function(pt){return pt.x + plus + pt.y}</code>
</p>

<p>
  Array: <span id="array"></span><br>
  &nbsp;&nbsp;fn: <code>function(pt){return [pt.x,'+',pt.y].join(' ')}</code>
</p>

<p>
  Array (no join): <span id="array_nojoin"></span><br>
  &nbsp;&nbsp;fn: <code>function(pt){return [pt.x,' + ',pt.y].join('')}</code>
</p>


<p>
  Array (replace comas): <span id="array_replace"></span><br>
  &nbsp;&nbsp;fn: <code>function(pt){return ([pt.x,'+',pt.y]+'').replace(',',' ')}</code>
</p>
</font>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

可以通过将字符串推送到数组来加速字符串连接。然后加入阵列。

["a","b","c"].join('');

这是因为join是一次调用,编译器也可以立即计算结果字符串的全长。

答案 2 :(得分:1)

这将取决于实现,但至少就V8(Chrome)而言,不,每个函数调用似乎都不会实例化新的' + '。很可能函数体被编译成一次性连接的操作。

您可以通过首先定义一个函数(在控制台中)来看到这一点:

var f = function(a, b) { return a + ' + ' + b; };

然后启动堆分析器并执行:

var c = f('1', '2');

探查器显示的是在此期间只分配了一个字符串:

"1 + 2"

这似乎意味着它甚至不将两个单独的连接操作视为单独的操作。它一次性完成所有这一切。

底线:像这样的微优化不太可能让你走得太远。正如Ismael指出的那样,它实际上可能会降低您的代码速度。