相同的代码放到一个稍微不同的地方很容易导致性能数倍的差异!
每次在写业务代码的时候,喜欢把把代码按照功能职责抽象成一个函数例如一下案例:
const isPhoneNum = phoneNum=> /^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/.test(phoneNum)
isPhoneNum('13222998778') && sendSms()
这样代码的可读性非常好,可以直接通过函数名读懂正则的含义。每次写多了,就产生了疑问,函数定义在时候的函数local本地还是定义在global区域呢?性能影响有多大?因此我写了如下两个case来验证下结果。
global.js
const add = (x, y) => {
return x + y;
}
const test = () => {
let result = 0;
for (let i = 0; i < 10000000; ++i) {
add(1, 2)
}
return result;
}
for (let i = 1; i <= 5; ++i) {
console.time("global function:" + i);
test();
console.timeEnd("global function:" + i);
}
local.js
const test = () => {
const add = (x, y) => {
return x + y;
}
let result = 0;
for (let i = 0; i < 10000000; ++i) {
add(1, 2)
}
return result;
}
for (let i = 1; i <= 5; ++i) {
console.time("local function:" + i);
test();
console.timeEnd("local function:" + i);
}
运行结果:
local function:1: 22.486ms
local function:2: 69.947ms
local function:3: 71.094ms
local function:4: 71.110ms
local function:5: 72.560ms
----------------------------
global function:1: 25.090ms
global function:2: 27.078ms
global function:3: 30.999ms
global function:4: 23.534ms
global function:5: 22.067ms
两个测试用例,我们用的是相同的代码,相同的测试逻辑,都运行在Node v7.10.1版本中,唯一的区别就是add函数的位置。
因此不要把功能函数定义在调用函数内容。
如有错误欢迎留言拍砖。
幸运的是,最新的V8已经优化过它了
@dislido V8 果然很屌~
好像是 V8 6.8 优化过了
吊
@justjavac local的代码更清晰,复杂嵌套,也都优化过么:)
@chapgaga 不。这个例子太特殊了,V8 并没有把里面的函数提到外面,而是直接把这个函数内联展开了。而且这个函数可以进行逃逸分析。
const test_local = () => {
const add_local = (x, y) => {
return x + y;
}
let result = 0;
for (let i = 0; i < 10000000; ++i) {
add_local(1, 2)
}
return result;
}
const add_global = (x, y) => {
return x + y;
}
const test_global = () => {
let result = 0;
for (let i = 0; i < 10000000; ++i) {
add_global(1, 2)
}
return result;
}
test_local();
% OptimizeFunctionOnNextCall(test_local);
test_local();
test_local();
test_global();
% OptimizeFunctionOnNextCall(test_global);
test_global();
test_global();
使用 node --allow-natives-syntax --print-opt-code xxx.js
运行:
...
--- Optimized code ---
optimization_id = 1
source_position = 81
kind = OPTIMIZED_FUNCTION
name = test_local
stack_slots = 7
compiler = turbofan
address = 0000030EE9B6DD61
Body (size = 316)
Instructions (size = 248)
...
--- Optimized code ---
optimization_id = 3
source_position = 337
kind = OPTIMIZED_FUNCTION
name = test_global
stack_slots = 6
compiler = turbofan
address = 0000030EE9B6E0C1
Body (size = 261)
Instructions (size = 208)
...
可以看到,两者还是有差别的,但是不是很大。
如果把最后几行去掉,直接使用 --print-bytecode
运行,就能看出差距来了