没有本地功能微观优化?

时间:2011-01-20 13:18:15

标签: javascript micro-optimization

将内部函数移到这个函数之外,以便每次调用函数时都不会创建它是微优化吗?

在这种特殊情况下,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);

} 

5 个答案:

答案 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慢了近一个数量级。

如果您正在编写性能非常重要的代码,那么最好避免使用内部函数。