我一直在使用函数指针p
来调用不同的函数。我的问题是,如果我在已经为它分配了一个函数后将它指向另一个函数,调用 p
的性能会急剧下降。如果我一遍又一遍地在 undefined
和同一个函数之间切换 p
性能很好,当我只将它指向一个函数时性能很好,但是在函数之间切换会降低性能.
下面是我用来测试这个场景的代码,这里是 fiddle .我以递归方式循环 500 次,并在每个循环中调用 p
1,000,000 次。 p
可以是 undefined
或指向 func1
或 func2
。
function func1() {} // two identical empty functions
function func2() {} // different in name only
var p = func1; // default to func1
var count = 0; // current loop
var elapse = 0; // elapsed time for 1,000,000 calls on each loop
var start = 0; // start time for 1,000,000 calls on each loop
var total = 0; // total elapsed time for all loops
function loop() {
start = performance.now(); // get start time
for (let i = 0; i < 1000000; i ++) if (p !== undefined) p(); // do 1,000,000 calls or early out 1,000,000 times if undefined
elapse = performance.now() - start;
total += elapse; // used for getting average
count ++;
console.log(p + "\nelapsed " + elapse + "\naverage " + total / count);
// Switch between the lines below to see the performance difference.
p = (p === func1) ? p = undefined : p = func1; // best performance
//p = (p === func1) ? p = func1 : p = func1; // good performance
//p = (p === func1) ? p = func2 : p = func1; // bad performance
// pattern: func1 -> undefined -> func2 -> undefined -> repeat
/*if (p === undefined) p = (count % 4 === 0) ? p = func1 : p = func2;
else p = undefined;*/ // also bad performance
if (count < 500) loop(); // start the next loop
}
console.clear();
loop(); // start the loop
为什么调用 p
的性能在分配给不同的函数时会显着下降?另外,为什么在将 p
设置为 undefined
时,将 p
设置为 undefined
并返回原始函数不会改变性能然后到不同的功能呢?
最佳答案
您正在阻止引擎创建优化的热路径,因为它不能依赖函数指针的值。
请参阅本文中标题为“JavaScript 引擎中的解释器/编译器管道”的部分:https://mathiasbynens.be/notes/shapes-ics
图片显示了 TurboFan 基于执行分析数据优化字节码,以及其后的文字说明:
To make it run faster, the bytecode can be sent to the optimizing compiler along with profiling data. The optimizing compiler makes certain assumptions based on the profiling data it has, and then produces highly-optimized machine code.
If at some point one of the assumptions turns out to be incorrect, the optimizing compiler deoptimizes and goes back to the interpreter.
当您重新分配函数指针时,您会将冲突的分析数据从解释器发送到编译器。当您分配未定义时不会发生这种情况,因为在这种情况下不会执行该代码路径:if (p !== undefined) p();
关于javascript - 为什么重新分配函数指针会减慢函数调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56381296/