将内部函数移到这个函数之外,以便每次调用函数时都不会创建它是微优化吗?
在这种特殊情况下,doMoreStuff
函数仅在doStuff
内使用。我应该担心像这样的本地功能吗?
function doStuff() {
var doMoreStuff = function(val) {
// do some stuff
}
// do something
for (var i = 0; i < list.length; i++) {
doMoreStuff(list[i]);
for (var j = 0; j < list[i].children.length; j++) {
doMoreStuff(list[i].children[j]);
}
}
// do some other stuff
}
一个例子就是说:
function sendDataToServer(data) {
var callback = function(incoming) {
// handle incoming
}
ajaxCall("url", data, callback);
}
答案 0 :(得分:4)
不确定这是否属于“微优化”类别。我会说不。
但这取决于你拨打doStuff
的频率。如果你经常调用它,那么一遍又一遍地创建函数是不必要的,肯定会增加开销。
如果你不想在全局范围内拥有“辅助函数”但是避免重新创建它,你可以像这样包装它:
var doStuff = (function() {
var doMoreStuff = function(val) {
// do some stuff
}
return function() {
// do something
for (var i = 0; i < list.length; i++) {
doMoreStuff(list[i]);
}
// do some other stuff
}
}());
由于返回的函数是闭包,因此它可以访问doMoreStuff
。请注意,外部函数会立即执行((function(){...}())
)。
或者您创建一个包含函数引用的对象:
var stuff = {
doMoreStuff: function() {...},
doStuff: function() {...}
};
有关封装,对象创建模式和其他概念的更多信息可以在书籍JavaScript Patterns中找到。
答案 1 :(得分:0)
这完全取决于调用函数的频率。如果它是一个每秒调用10次的OnUpdate函数,那么它就是一个不错的优化。如果每页调用三次,则为微优化。
虽然方便,但从不需要嵌套函数定义(可以用函数的额外参数替换它们)。
嵌套函数示例:
function somefunc() {
var localvar = 5
var otherfunc = function() {
alert(localvar);
}
otherfunc();
}
同样的事情,现在改为参数:
function otherfunc(localvar) {
alert(localvar);
}
function somefunc() {
var localvar = 5
otherfunc(localvar);
}
答案 2 :(得分:0)
这绝对是一种微观优化。首先使用函数的全部原因是为了使代码更清晰,更易于维护和更易读。函数为代码段添加语义边界。每个函数应该只做一件事,它应该干净利落。因此,如果您发现您的函数同时执行多个操作,那么您可以将其重构为多个例程。
只有当你的工作太慢时才会优化(如果它还没有工作,那么优化还为时过早。期间)。请记住,没有人为一个比他们的需求/要求更快的程序支付额外费用......
编辑:考虑到程序尚未完成,它也是一个不成熟的优化。为什么那么糟糕?好吧,首先,你花时间研究一些从长远来看可能无关紧要的事情。其次,您没有基线来查看您的优化是否在实际意义上改进了任何内容。第三,你甚至在运行之前就降低了可维护性和可读性,所以运行起来比使用干净简洁的代码要困难。第四,你不知道你是否需要doMoreStuff
程序中的其他地方,直到你完成它并了解你的所有需求(可能是一个长视图取决于具体细节,但不是在可能性范围之外)。
有一个原因,Donnald Knuth说过早优化是所有邪恶的根源 ...
答案 3 :(得分:0)
快速“基准”在普通PC上运行(我知道有很多未解释的变量,因此不要对显而易见的事情发表评论,但在任何情况下它都很有趣):
count = 0;
t1 = +new Date();
while(count < 1000000) {
p = function(){};
++count;
}
t2 = +new Date();
console.log(t2-t1); // milliseconds
可以通过将增量移动到条件来优化它(使运行时间减少大约100毫秒,尽管它不会影响有和没有函数创建之间的差异,所以它并不是真的相关)
跑了3次给了:
913
878
890
然后注释掉函数创建行,3次运行给出:
462
458
464
因此,纯粹在1000,000个空函数创建中,您可以添加大约半秒钟。即使假设您的原始代码在手持设备上每秒运行10次(假设设备整体性能是这台笔记本电脑的1/100,这是夸张的 - 它可能接近1/10,尽管会提供一个很好的上限) ,这相当于这台计算机上的1000个功能创建/秒,发生在1/2000秒。因此,手持设备的每一秒都会增加1/2000秒的处理开销......每秒半毫秒不是很多。
从这个原始测试中我得出结论,在PC上这绝对是一种微优化,如果你是为较弱的设备开发的,那几乎可以肯定。
答案 4 :(得分:0)
最初的问题是在2011年提出的。鉴于Node.js自那时起兴起,我认为值得重新审视这个问题。在服务器环境中,这里和那里几毫秒可能很重要。在负载下保持响应之间可能存在差异。
虽然内部函数在概念上很好,但它们可能会给JavaScript引擎的代码优化器带来问题。以下示例说明了这一点:
function a1(n) {
return n + 2;
}
function a2(n) {
return 2 - n;
}
function a() {
var k = 5;
for (var i = 0; i < 100000000; i++) {
k = a1(k) + a2(k);
}
return k;
}
function b() {
function b1(n) {
return n + 2;
}
function b2(n) {
return 2 - n;
}
var k = 5;
for (var i = 0; i < 100000000; i++) {
k = b1(k) + b2(k);
}
return k;
}
function measure(label, fn) {
var s = new Date();
var r = fn();
var e = new Date();
console.log(label, e - s);
}
for (var i = 0; i < 4; i++) {
measure('A', a);
measure('B', b);
}
运行代码的命令:
node --trace_deopt test.js
输出:
[deoptimize global object @ 0x2431b35106e9]
A 128
B 130
A 132
[deoptimizing (DEOPT eager): begin 0x3ee3d709a821 b (opt #5) @4, FP to SP delta: 72]
translating b => node=36, height=32
0x7fffb88a9960: [top + 64] <- 0x2431b3504121 ; rdi 0x2431b3504121 <undefined>
0x7fffb88a9958: [top + 56] <- 0x17210dea8376 ; caller's pc
0x7fffb88a9950: [top + 48] <- 0x7fffb88a9998 ; caller's fp
0x7fffb88a9948: [top + 40] <- 0x3ee3d709a709; context
0x7fffb88a9940: [top + 32] <- 0x3ee3d709a821; function
0x7fffb88a9938: [top + 24] <- 0x3ee3d70efa71 ; rcx 0x3ee3d70efa71 <JS Function b1 (SharedFunctionInfo 0x361602434ae1)>
0x7fffb88a9930: [top + 16] <- 0x3ee3d70efab9 ; rdx 0x3ee3d70efab9 <JS Function b2 (SharedFunctionInfo 0x361602434b71)>
0x7fffb88a9928: [top + 8] <- 5 ; rbx (smi)
0x7fffb88a9920: [top + 0] <- 0 ; rax (smi)
[deoptimizing (eager): end 0x3ee3d709a821 b @4 => node=36, pc=0x17210dec9129, state=NO_REGISTERS, alignment=no padding, took 0.203 ms]
[removing optimized code for: b]
B 1000
A 125
B 1032
A 132
B 1033
如您所见,功能A和B最初以相同的速度运行。然后由于某种原因发生了去优化事件。从那以后,B慢了近一个数量级。
如果您正在编写性能非常重要的代码,那么最好避免使用内部函数。