变量名称长度与性能

Ste*_*kas 5 javascript variables performance naming-conventions

怎么可能,变量名长度的巨大差异不会导致javascript中的任何性能损失?

这需要同时声明var a = 0;,因为它需要声明var aaaaaaaaaaaaaaa = 0; 它需要的同时,甚至与他们进行计算.

我的小提琴演示

Dmi*_*try 7

window.a = 2;
window.b = 3;
window.c = 4;
window.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 2;
window.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 3;
window.ccccccccccccccccccccccccccccccccccccccccccccccccc = 4;    
var ts = [];

var t = performance.now();
for(var i = 0; i < 1000000; ++i) {
    a = b + c;
}
ts.push(performance.now() - t);

var t = performance.now();
for(var i = 0; i < 1000000; ++i) {
    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+ ccccccccccccccccccccccccccccccccccccccccccccccccc;
}
ts.push(performance.now() - t);

console.log(ts);
Run Code Online (Sandbox Code Playgroud)

在浏览器控制台中运行以上10次给我以下统计数据,a = b + c,a = b ... + c ...对:

[4.050000000046566, 4.614999999990687]
[4.254999999946449, 4.59499999997206]
[4.054999999993015, 4.584999999962747]
[4.869999999995343, 5.4500000000116415]
[4.074999999953434, 4.570000000006985]
[4.099999999976717, 4.775000000023283]
[4.205000000016298, 4.649999999965075]
[4.205000000016298, 4.669999999983702]
[4.159999999974389, 4.720000000030268]
[4.149999999965075, 4.684999999997672]
Run Code Online (Sandbox Code Playgroud)

较长的版本始终较慢.

在局部变量的情况下,这是不同的,因为它们被编译一次并通过索引而不是名称使用getlocal/setlocal指令引用.所以让我们看..

(function() {
    var a = 2;
    var b = 3;
    var c = 4;
    var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = 2;
    var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 3;
    var ccccccccccccccccccccccccccccccccccccccccccccccccc = 4;    
    var ts = [];

    var t = performance.now();
    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
    ts.push(performance.now() - t);

    var t = performance.now();
    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb+ ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
    ts.push(performance.now() - t);

    console.log(ts);
})();

[2.5850000000791624, 2.2100000000791624] (longer wins)
[2.7950000000419095, 2.525000000023283] (shorter wins)
[2.4699999999720603, 2.4200000000419095] (longer wins)
[2.64000000001397, 2.2449999999953434] (longer wins)
[2.669999999925494, 2.469999999855645] (longer wins)
[2.5200000000186265, 2.7800000000279397] (shorter wins)
[2.4600000000791624, 2.3950000000186265] (longer wins)
[3.2900000001536682, 3.1299999998882413] (longer wins)
[3.1949999999487773, 3.1850000000558794] (longer wins)
[3.8049999999348074, 3.0200000000186265] (longer wins)
Run Code Online (Sandbox Code Playgroud)

虽然在大多数迭代中它们确实变化很大,但是在很多情况下,较长的变量名称比较短的变量名称更快(一个天真的观察者可能会得出结论,较长的名称使其更快).这是因为名称仅在编译范围时相关; 实际执行的指令不是按名称引用变量.

我的结论是; 保持全局变量名称简短,局部变量名称将略微增加从文本到指令的转换,但在此之后,它无关紧要.

我假设javascript与actionscript的工作原理类似,它处理变量,所以这里是两个字节码并排的动作脚本转储.(Adobe Flash CS3;使用JPEXS免费Flash反编译器反编译).

var a;
var b = 2;
var c = 3;
var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2;
var ccccccccccccccccccccccccccccccccccccccccccccccccc = 3;    

function long_global()
{        
    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
}

function short_global()
{
    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
}

function long_local()
{        
    var aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa;
    var bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb = 2;
    var ccccccccccccccccccccccccccccccccccccccccccccccccc = 3;

    for(var i = 0; i < 1000000; ++i) {
        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + ccccccccccccccccccccccccccccccccccccccccccccccccc;
    }
}

function short_local()
{
    var a;
    var b = 2;
    var c = 3;

    for(var i = 0; i < 1000000; ++i) {
        a = b + c;
    }
}
Run Code Online (Sandbox Code Playgroud)

long_global编译为:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 24 00
pushbyte 0
; 82
coerce_a
; d5
setlocal_1
; 10 0e 00 00
jump ofs001b
; 09
ofs000d:label
; 5e 0a
findproperty Qname(PackageNamespace(""),"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
; 60 09
getlex Qname(PackageNamespace(""),"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
; 60 06
getlex Qname(PackageNamespace(""),"ccccccccccccccccccccccccccccccccccccccccccccccccc")
; a0
add
; 68 0a
initproperty Qname(PackageNamespace(""),"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
; d1
getlocal_1
; 91
increment
; 82
coerce_a
; d5
setlocal_1
; d1
ofs001b:getlocal_1
; 2d 01
pushint 1000000
; 15 eb ff ff
iflt ofs000d
; 47
returnvoid
Run Code Online (Sandbox Code Playgroud)

short_global编译为

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 24 00
pushbyte 0
; 82
coerce_a
; d5
setlocal_1
; 10 0e 00 00
jump ofs001b
; 09
ofs000d:label
; 5e 08
findproperty Qname(PackageNamespace(""),"a")
; 60 05
getlex Qname(PackageNamespace(""),"b")
; 60 04
getlex Qname(PackageNamespace(""),"c")
; a0
add
; 68 08
initproperty Qname(PackageNamespace(""),"a")
; d1
getlocal_1
; 91
increment
; 82
coerce_a
; d5
setlocal_1
; d1
ofs001b:getlocal_1
; 2d 01
pushint 1000000
; 15 eb ff ff
iflt ofs000d
; 47
returnvoid
Run Code Online (Sandbox Code Playgroud)

long_local:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 21
pushundefined
; 82
coerce_a
; d6
setlocal_2
; 21
pushundefined
; 82
coerce_a
; d7
setlocal_3
; 21
pushundefined
; 82
coerce_a
; 63 04
setlocal 4
; 24 02
pushbyte 2
; 82
coerce_a
; d6
setlocal_2
; 24 03
pushbyte 3
; 82
coerce_a
; d7
setlocal_3
; 24 00
pushbyte 0
; 82
coerce_a
; 63 04
setlocal 4
; 10 0c 00 00
jump ofs002c
; 09
ofs0020:label
; d2
getlocal_2
; d3
getlocal_3
; a0
add
; 82
coerce_a
; d5
setlocal_1
; 62 04
getlocal 4
; 91
increment
; 82
coerce_a
; 63 04
setlocal 4
; 62 04
ofs002c:getlocal 4
; 2d 01
pushint 1000000
; 15 ec ff ff
iflt ofs0020
; 47
returnvoid
Run Code Online (Sandbox Code Playgroud)

short_local:

; d0
getlocal_0
; 30
pushscope
; 21
pushundefined
; 82
coerce_a
; d5
setlocal_1
; 21
pushundefined
; 82
coerce_a
; d6
setlocal_2
; 21
pushundefined
; 82
coerce_a
; d7
setlocal_3
; 21
pushundefined
; 82
coerce_a
; 63 04
setlocal 4
; 24 02
pushbyte 2
; 82
coerce_a
; d6
setlocal_2
; 24 03
pushbyte 3
; 82
coerce_a
; d7
setlocal_3
; 24 00
pushbyte 0
; 82
coerce_a
; 63 04
setlocal 4
; 10 0c 00 00
jump ofs002c
; 09
ofs0020:label
; d2
getlocal_2
; d3
getlocal_3
; a0
add
; 82
coerce_a
; d5
setlocal_1
; 62 04
getlocal 4
; 91
increment
; 82
coerce_a
; 63 04
setlocal 4
; 62 04
ofs002c:getlocal 4
; 2d 01
pushint 1000000
; 15 ec ff ff
iflt ofs0020
; 47
returnvoid
Run Code Online (Sandbox Code Playgroud)

long_global和short_global的字节码大小; short_local和long_local分别是equivelent,但在本地情况下,它们不是通过名称引用的,只能通过setlocal和getlocal引用; 而在全局情况下,它们由字符串键所在的索引引用; 我的猜测是,较长的一个需要更长的时间来散列来获取指示物,而较短的一个需要更短的时间来散列以获得指示物才能被使用.


Ste*_*kas 5

基于@ Cerbrus的评论:

它在实践中导致可忽略的小的性能差异,但仅在声明变量时.之后,它在内存中获取一个特定的地址,并将其称为此地址,而不是变量名称,因此它不再影响性能.


但是,谈论主要在Web上使用的脚本语言,较短的变量名称可以减少文件大小,并加快页面加载速度.这是JS编译器的功能之一,例如Google的.

  • 并非总是如此;只有局部变量(例如显式参数和范围变量)才是这种情况。当您执行诸如window.bar = 2之类的操作时,并没有使用getlocal_index进行引用,它必须使用字符串bar并通过对名称进行散列来查找实际值。因此,在声明它之后,window.gkijqjqiwiwiwododo = window.qwdoijqwodjqoiwjdiqjwdiwq + window.cjqjiwjqijwijwijwiwiwk的运行速度会比window.a = window.b + window.c慢很多。Kinda现在想测试一下。 (2认同)