【发布时间】:2021-12-27 13:26:48
【问题描述】:
当 class 和 defined variables 被实例化时,我注意到 Javascript 中有一些奇怪的行为。
注意:下面的代码只是作为这个特定问题的再现案例。
让我们考虑以下类:
class Vector3
{
#unused1;
#unused2;
#unused3;
#unused4;
#unused5;
#unused6;
#unused7;
#unused8;
#unused9;
#unused10;
#unused11;
#unused12;
#unused13;
constructor(x, y, z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
还有以下脚本:
let frames = 0;
let p = 0;
let fn = () => {
let now = performance.now();
let sum;
for (let i = 0; i < 10000; i++) {
var vector = new Vector3(Math.random(),Math.random(),Math.random());
var o = new Vector3(vector.x + Math.random(), vector.y + Math.random(), vector.z + Math.random());
}
// check the amount of passed frames every second
if (now - p >= 1000) {
console.log(frames);
// added to also test performance without having Dev Tools open
document.documentElement.innerText = frames;
frames = 0;
p = now;
}
frames++;
requestAnimationFrame(() => {
return fn();
})
return;
}
fn();
当运行上述程序并查看控制台时,我们可以看到性能约为(取决于您的规格)30 到 35 帧。
现在,如果我们将类修改为不包含已定义的变量:
class Vector3
{
constructor(x, y, z)
{
this.x = x;
this.y = y;
this.z = z;
}
}
我们可以看到性能上升到(同样,取决于您的规格)60 帧及以上。
起初我认为这个问题与garbage collection 有关,但在检查Chrome Profiler 之后,我注意到大部分性能被getting 变量吞噬,经过进一步研究/基准测试后,我注意到这个问题没有t实际上与变量in use有关,但变量declared。
另外需要注意的是,如果将变量声明为 private 或 public,这似乎并不“重要”。
有人解释为什么会出现这个问题吗?
更新:这个问题似乎对Chromium 的影响大于Firefox。 Firefox "always" 似乎达到了 60。
【问题讨论】:
-
声明属性告诉运行时它应该在分配的对象中为它们腾出空间。即使它们没有被使用,对象也更大,因此您的循环总体上分配了相当多的内存。
-
#unused1等是private fields,而不是“声明的变量”。如果未启用分析器,性能问题是否仍然存在? -
@SebastianSimon 在这种情况下,探查器本身似乎不会影响性能。开发工具是否打开也不行。
-
不声明你不会使用的变量当然是个好主意。然而,另一方面,通过声明您实际将使用的私有字段意味着分配机制可以分配适当大小的对象。如果没有声明,添加新属性本身就会造成性能损失。
-
@BRO_THOM 好吧,getter/setter 不需要在内存中为类的每个实例复制,这与字段(必须是每个实例)不同。
标签: javascript ecmascript-6 chromium es6-class