为什么在Javascript中调用函数这么慢?

时间:2015-06-09 00:18:13

标签: javascript performance

这是我最近注意到的一些奇怪的事情:调用函数似乎比内部函数花费更长的时间。如this fiddle

jQuery('button').click(function(){
    console.time('outer')
    dostuff.call(this)    
    console.timeEnd('outer')
})

dostuff = function(){
 console.time('inner')
 jQuery(this).css('background','red')
 jQuery(this).css('border','solid black')
 jQuery(this).css('margin','0 5px 0')
 jQuery(this).css('padding','0px')
 console.timeEnd('inner')
}

控制台输出显示外部比实际工作要慢得多...为什么会发生这种情况,更重要的是,如何在时间关键代码中减少这个时间?

outer: timer started show:23
17:12:49.020 inner: timer started show:29
17:12:49.021 inner: 1.8ms show:34
17:12:49.023 outer: 5.1ms show:25
17:12:51.368 outer: timer started show:23
17:12:51.368 inner: timer started show:29
17:12:51.370 inner: 1.2ms show:34
17:12:51.370 outer: 2.47ms show:25
17:12:54.094 outer: timer started show:23
17:12:54.095 inner: timer started show:29
17:12:54.096 inner: 1.92ms show:34
17:12:54.098 outer: 3.67ms

1 个答案:

答案 0 :(得分:1)

微观基准可能会产生误导,这也是他们普遍气馁的原因。为了正确地测量任何事情的时间安排,你通常需要做足够多的有意义的工作(导致副作用的工作,而不是说工作,暂时只计算丢弃它的工作)。否则,您将开始考虑更多动态因素的时间(缓存,分页,单个分支错误预测等)。

您的问题有点过于宽泛,因为准确回答它需要精确了解正在使用的精确JavaScript引擎的内部。我们必须知道编译器发出的确切反汇编,以及何时,确切地说。虽然如果您陈述正在使用的JavaScript引擎,它可能会帮助您获得更准确的答案。

也就是说,如果您正在使用JIT,就像您可能已经知道的那样,即时编译器可以即时翻译指令(到字节码IR或直接转换为机器代码)。

其中一些基于每个功能进行翻译。如果是这种情况,您会发现首次使用功能的初始费用远远高于后续通话费用,因为您已经支付了#34;首次遭遇&#34 ; JIT遇到新代码的开销。

如果您正在使用跟踪JIT,那么JIT将分析执行的常见案例分支("热路径"),您同样可以看到一种"首先 - 遇到"跟踪代码路径的开销,直到建立执行的常见案例分支。

无论如何,所有这些都是假设的,但值得注意的是,对于许多JIT,首次执行代码的性能明显偏差(比后续执行同一代码要贵得多)。这可能会解释您的结果,也可能不会。

但无论情况如何,您通常都希望避开微基准测试,特别是涉及越来越多的动态因素(脚本语言比本机代码增加了很多)。我们现在正在使用非常复杂的硬件和编译器来尝试为我们预测事物,在动态编译代码的情况下,我们还有另外一个元素,除了硬件和操作系统在运行中。当我们开始在过于细化的水平上测量事物时,结合这些动态因素,我们停止测量代码的速度,而是开始逆向工程这些动态因素。