在V8中扩展JavaScript数组并保持PACKED类型

时间:2019-07-08 22:24:52

标签: javascript inheritance optimization v8

我已经阅读了packed arrays in the V8 engine,并希望将它们用于游戏中一些性能至关重要的部分(例如,作为粒子的容器)。

我想制作一个自定义的Array子类,该子类将始终保持打包状态,但似乎无法用另一个数组扩展self。

<html>
<head>
  <link ref="stylesheet" href="dist/style.css"/>
</head>
<body>
  <script src="dist/app.built.js"></script>
</body>
</html>

是否可以扩展子类数组实例并在V8中保持PACKED类型?

我知道我可以一一推送值,甚至可以调用class PackedArray extends Array { constructor() { super(); } extend(values) { // `values` is another array. // This obviously won't work, is there another way? this = this.concat(values); } } ,但是它比this.push(...values)慢,并且对于大型数组失败。

2 个答案:

答案 0 :(得分:2)

V8开发人员在这里。 TL; DR:“打包元素”可以做的最好的事情就是不用担心它们。差异几乎无法测量。

在某些微基准测试中,在针对热核循环的优化代码中只有少量机器指令,每条指令都很重要,并且如果当前元素的“空洞”检查是其中之一(实际上是两个) :{x1上的cmp + je),然后跟踪不需要的阵列会影响基准分数。但是,在实际应用中,您需要对数组元素执行非平凡的操作,因此无法测量两条机器指令的影响。自定义包装程序类遇到的任何扭曲都可能比您可以节省的少量开销贵。


通过使用“具有”而不是“具有”组成部分可以解决您提出的具体问题:

class PackedArray {
  extend(values) {
    this.#data = this.#data.concat(values);
  }
  get(i) { return this.#data[i]; }

  #data = [];
}

这还将解决以下问题:对于子类,代码仍然可以使用my_packed_array[10000] = "now you have holes"来绕过.extend()方法。但是,请记住我在上面写的内容:孔检查的影响是很小的,所有这些额外的包装所花费的成本都可能比保存的成本高。

编辑:@MathiasBynens写的也是一个很好的观点:不要为V8优化,让V8为您优化! :-)

答案 1 :(得分:0)

您可以使用this.splice()修改当前数组。

extend(values) {
    this.splice(this.length, 0, ...values);
}