相同的代码放到一个稍微不同的地方很容易导致性能数倍的差异!
发布于 6 年前 作者 lvgithub 3172 次浏览 来自 分享

相同的代码放到一个稍微不同的地方很容易导致性能数倍的差异!

每次在写业务代码的时候,喜欢把把代码按照功能职责抽象成一个函数例如一下案例:

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函数的位置。

因此不要把功能函数定义在调用函数内容。

如有错误欢迎留言拍砖。

测试代码_Github

7 回复

幸运的是,最新的V8已经优化过它了 image.png

@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 运行,就能看出差距来了

回到顶部