最初的问题是在 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 几乎慢了一个数量级。
如果您正在编写注重性能的代码,最好避免使用内部函数。