我最近在Node JS做了很多工作,重点是异步模块让我依赖于在闭包上应用绑定函数来包装循环内的异步调用(以保留函数调用时的变量值)。 这让我思考。将变量绑定到函数时,可以将传递的值添加到该函数的本地范围。因此,在Node(或任何经常引用范围变量的JS代码)中,将范围变量(例如模块)绑定到函数是否有利,以便在使用时它们是本地范围的一部分?
简单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/
注意:节点的REPL测试不可靠,因为它必须使用某种缓存系统。在func1的单个基准测试之后,func2返回0ms。
随意提供更好的基准测试结果。
答案 0 :(得分:2)
通常,减少范围查找的效果应该是积极的。然而,在今天的快速JS引擎上,差异可能相当微小。
在一些运行在较旧的JS引擎上的数学密集型代码中,我曾经通过这样的方式获得更多性能:
function doSomething() {
var round = Math.round;
var floor = Math.floor;
//Do something that calls floor and round a lot
}
所以基本上把函数外部的函数带到函数自己的范围可以有积极的作用,但是要确保你可能应该对代码进行分析以确定。
答案 1 :(得分:2)
正如您的评论中的一些用户指出的那样,绑定功能会增加一些开销,因此它并不是真正的准确比较。你应该通过使用参数调用函数来测试它,而不是用另一个函数包装它来将参数绑定到它。
这是一个测试(cwolves的原始测试):
http://jsperf.com/outer-vs-inner-references/2
设置:
var x = 10, y = 11, z = 12, z = 13, a = 14, g = 15;
测试用例#1(外部参考):
(function(){
for(var i=0; i<1000; i++){
x + y + z + a + g
}
})();
测试案例#2(本地参考):
(function(x,y,z,a,g){
for(var i=0; i<1000; i++){
x + y + z + a + g;
}
})(x,y,z,a,g);
<强>结果:
根据此测试,第二个测试用例比第一个测试用例快得多。老实说,我有点惊讶,我想知道我自己的测试是否有缺陷。我知道它会更快,但认为差异可以忽略不计 - 但显然不是吗?
答案 2 :(得分:1)
基于我完成的一些基准(见问题)和Jani的建议,似乎在今天的新时代浏览器范围问题已经通过V8等快速引擎得到缓解。理论上,减少观察范围的数量应该会提高速度,但测试并不支持这一点 对于那些专门处理Node.JS的人来说,你需要担心的唯一开销是函数的第一次迭代。当在Node中重复调用某些内容时,似乎V8引擎能够缓存部分函数的执行以供以后使用。为了避免这种缓存,func2使用了大量的迭代。简单的数学表明,在缩放func2的测试后,它比func1慢大约5.6ms。鉴于你在大多数浏览器中可以看到的波动,我猜两者都可能在5ms到15ms之间跳动。我会建议,坚持使用func1方法,因为它似乎有一点点优势,并得到更广泛的支持(我正在看你的IE lt 9)。