绑定超出范围variables可以加快你的代码?

我最近在Node JS上做了很多工作,而且我强调asynchronous模块是依靠在闭包上应用绑定函数来将asynchronous调用包装在循环中(以在函数调用中保留variables的值)。 这让我思考。 将variables绑定到函数时,将传递的值添加到该函数的本地作用域。 因此,在Node(或任何经常引用作用域variables的JS代码)中,将范围variables(例如模块)绑定到函数外是否有利,以便在使用时它们是本地作用域的一部分?

普通的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) 

节点中的示例

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

在我上面的例子中,func1或者func2会比其他的更快(不包括外部因素,比如获取文件统计所花费的时间)?


这里有一个JSFiddle我扔在一起,做一个快速和肮脏的基准: http : //jsfiddle.net/AExvz/

  1. Google Chrome 14.0.797.0 dev-m
    • Func1:2-4ms
    • Func2:30-46ms
  2. Google Chrome 14.0.800.0 canary
    • Func1:2-7ms
    • Func2:35-39ms
  3. Firefox 5.0
    • Func1:0-1ms
    • Func2:35-42ms
  4. Opera 11.11 Build 2109
    • function1:21-32ms
    • Func2:68-73ms
  5. Safari 5.05(7533.21.1)
    • function1:23-34ms
    • Func2:71-78ms
  6. Internet Explorer 9.0.8112.16421
    • Func1:10-17ms
    • Func2:14-17ms
  7. 节点0.4.8 REPL
    • Func1:10ms
    • Func2:156ms @ 10倍以上的迭代(〜15.6ms,如果两者都经过100000次迭代testing)

注意:节点的REPLtesting是不可靠的,因为它必须使用某种caching系统。 在func1的一个基准testing之后,func2返回了0ms。

随意贡献一个更好的基准的结果。

一般来说,缩小范围查找的效果应该是正面的。 然而,在今天的JS引擎上,差别可能相当小。

在一些老式的JS引擎上运行的一些math密集的代码中,我曾经通过这样做来获得更多的性能:

 function doSomething() { var round = Math.round; var floor = Math.floor; //Do something that calls floor and round a lot } 

所以基本上把函数外部的函数带到函数本身的范围内可以产生积极的效果,但是可以肯定的是你可能应该对代码进行简单的描述。

正如你的评论中的一些用户指出的那样,绑定函数会增加一些开销,所以这不是一个真正的比较。 你应该通过调用带有参数的函数来testing它,而不是用另外一个函数来包装参数。

这是一个testing来certificate(原始testing由cwolves):

http://jsperf.com/outer-vs-inner-references/2

build立:

 var x = 10, y = 11, z = 12, z = 13, a = 14, g = 15; 

testing用例#1(外部参考):

 (function(){ for(var i=0; i<1000; i++){ x + y + z + a + g } })(); 

testing用例#2(本地参考):

 (function(x,y,z,a,g){ for(var i=0; i<1000; i++){ x + y + z + a + g; } })(x,y,z,a,g); 

结果

根据这个testing,第二个testing案例比第一个案例要快得多。 老实说,我有点惊讶,想知道我自己的testing是否有缺陷。 我知道这会更快,但认为差异可以忽略不计 – 但显然不是?

根据我完成的一些基准(见问题)和Jani的build议,似乎今天的新时代浏览器的范围问题已经被像V8这样的快速引擎缓解了。 从理论上讲,减less示波器查找的次数应该会提高速度,但是testing并不支持这一点。
对于那些专门处理Node.JS的人来说,似乎唯一需要担心的开销就是函数的第一次迭代。 当在Node中重复调用某些内容时,似乎V8引擎能够caching部分函数的执行以供以后使用。 为了避免这种caching,func2使用了大量的迭代。 简单的math表明,在对func2进行testing之后,它比func1慢了约5.6ms。 鉴于你在大多数浏览器中可以看到的波动,我猜测两者可能在5ms到15ms之间跳动。 我会build议,但坚持func1的方法,因为它似乎有一个轻微的优势,并得到更广泛的支持(我在看你IE 9)。