🎲
Node16, 18 では arr.at(-1) は arr[arr.length-1] より遅い
OSSやってて教えてもらったんですが、Node.js 16 から使えるようになっている Array.prototype.at
は、実は Node16, Node18 では通常のプロパティアクセスに比べて大幅に遅いらしいです。
実際に計測してみました。
計測スクリプトはこちらです。ちょっと長いですが、array[array.length - 1]
と array.at(-1)
をそれぞれ 1e8 回実行するのにかかった時間を PerformanceObserver
で計測しているだけです。(リポジトリは https://github.com/sosukesuzuki/array-prototype-at-perf/tree/main )
const { PerformanceObserver, performance } = require("node:perf_hooks");
const marks = {
propertyAccess: {
start: "START_PROPERTY_ACCESS",
end: "END_PROPERTY_ACCESS",
},
arrayPrototypeAt: {
start: "START_ARRAY_PROTOTYPE_AT",
end: "END_ARRAY_PROTOTYPE_AT",
},
};
const observer = new PerformanceObserver((items) => {
const perfEntries = items
.getEntries()
.sort((a, b) => (a.name.length < b.name.length ? 1 : -1));
for (const perfEntry of perfEntries) {
const targetLength = perfEntries[0].name.length;
console.log(
perfEntry.name.padEnd(targetLength, " "),
`${perfEntry.duration} ms`
);
}
performance.clearMarks();
});
observer.observe({ type: "measure" });
const array = [1, 2, 3];
performance.mark(marks.propertyAccess.start);
for (let i = 0; i < 1e8; i++) {
array[array.length - 1];
}
performance.mark(marks.propertyAccess.end);
performance.measure(
"array[array.length -1]",
marks.propertyAccess.start,
marks.propertyAccess.end
);
performance.mark(marks.arrayPrototypeAt.start);
for (let i = 0; i < 1e8; i++) {
array.at(-1);
}
performance.mark(marks.arrayPrototypeAt.end);
performance.measure(
"array.at(-1)",
marks.arrayPrototypeAt.start,
marks.arrayPrototypeAt.end
);
このスクリプトを Node.js 16, Node.js 18, Node.js 19 でそれぞれ実行した結果が以下です。
Node.js 16:
array[array.length -1] 47.548583984375 ms
array.at(-1) 2733.349083006382 ms
Node.js 18:
array[array.length -1] 47.59833401441574 ms
array.at(-1) 2463.5460420250893 ms
Node.js 19:
array[array.length -1] 47.45416694879532 ms
array.at(-1) 62.53858298063278 ms
スーパー遅い!こんなに遅いなら、Node.js 16, 18 ではまだ Array.prototype.at
は使わない方がよいかもしれませんね。
Node.js 18 の V8 が 10.1 で Node.js 19 の V8 が 10.7 らしいので、その間の V8 でなにかしらの最適化が入ったのだと思うんですが、私のV8力では該当コミットを見つけることができませんでした。知っている人は教えてほしいです。
Discussion