我应该静态分配Javascriptstring的内存性能?
所以我正在写这个node.js应用程序,我试图让它超快速,并且占用内存很less。 我有很多string连接,function如下:
function f(pt) { return pt.x + ' + ' + pt.y; }
如果我在应用程序的内部循环中执行了1亿次这样的操作,JavaScript引擎是否需要分配并且必须释放string' + '
1亿次? 将这些代码重写成类似的东西,会不会是更高效的记忆方式?
var plus = ' + '; function f(pt) { return pt.x + plus + pt.y; }
还是编译器只是在后台执行这个操作,还是不要紧? (我的代码实际上使用的string比“+”长得多,我只是用它作为例子)。
这取决于。
但说实话,这可能会慢一些。
这是因为它必须在函数范围内searchvariablesplus
,然后在窗口对象上面find它。
所以,我相信可能会慢一些。
考虑下面的代码:
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%!
在下面,您可以看到大致相同的时间:
你也可以在电脑上testing它!
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串联可以通过将string推入数组来加速。 然后join数组。
["a","b","c"].join('');
这是因为join是一个调用,编译器也可以立即计算结果string的全长。
这将取决于实现,但至less就V8(Chrome)而言,不,每个函数调用都不会实例化一个新的' + '
。 最有可能的是,函数体被编译成一次连接的操作。
您可以通过首先定义一个函数(在控制台中)来看到这一点:
var f = function(a, b) { return a + ' + ' + b; };
然后启动堆分析器并执行此操作:
var c = f('1', '2');
分析器显示的是在此期间只分配一个string:
"1 + 2"
这似乎意味着它甚至不把这两个单独的连接操作视为单独的操作。 这一切都是一回事。
底线:这样的微观优化不可能让你走得更远。 正如Ismael指出的那样,这实际上可能会减慢你的代码速度。