So I was working on some benchmarking with a piece of code in JavaScript and I was scratching my head over the runtimes that I was seeing. I literally could not make sense of what was happening. And in a wild attempt at debugging, I stumbled upon a quirk that I had never known.
The v8 engine does not really like the delete
operator. And using this operator on an object can have a tangible impact on the performance of your code. In my case, it was almost 3 times worse performance than if I had manually set that key to undefined
or false
That said, I was able to reproduce this in Safari v18.5 as well along with all Chromium based browsers. So not really sure if this behavior is limited to the v8 engine.
Benchmarking code
Here’s a simple code I wrote based on my experience to easily benchmark the performance impact of using delete vs. manually setting the key to something else. Note that in the code example here I’m setting it to false but using undefined yields similar results.
const mapDelete = {};
const benchmarkDelete = (i = 0) => {
while (i < 25) {
if (mapDelete[i]) {
delete mapDelete[i];
} else mapDelete[i] = true;
benchmarkDelete((i += 1));
}
};
const startDelete = performance.now();
benchmarkDelete();
const endDelete = performance.now();
console.log(`Execution time delete => ${endDelete - startDelete} milliseconds`);
const mapFalse = {};
const benchmarkFalse = (i = 0) => {
while (i < 25) {
if (mapFalse[i]) {
mapFalse[i] = false;
} else mapFalse[i] = true;
benchmarkFalse((i += 1));
}
};
const startFalse = performance.now();
benchmarkFalse();
const endFalse = performance.now();
console.log(`Execution time false => ${endFalse - startFalse} milliseconds`);
I ran this code in multiple environments such as Chrome, Safari and node and the results were more or less consistent. The first method’s execution time was around 3 times slower than that of the second method.
Node
I tested with v24.2.0
which was the latest available version at the time of writing this article.
Chrome
Tested on Version 136.0.7103.114 (Official Build) (arm64)
on macOS 15.5
Safari
While Chrome and Node are both using Google’s v8 engine, Safari uses Apple’s own engine called JavaScriptCore, also known as Nitro. Tested on Safari 18.5 on macOS 15.5.
Why?
I tried to find the exact reason but I couldn’t really find anything definitive or official, but I did come across a couple of other articles and posts on StackOverflow talking about this or something close to this. The logic seems to be that when you use delete the underlying JS engine stops treating it like a conventional hash map and loses some of the optimizations it has for working with them.
This post goes into a lot more details about the underlying optimizations that v8 engine does, but I think something similar applies to most other engines as well.
TL;DR
If you care about the runtime and performance of your code/app and heavily use delete
for objects that are used as lookups with very frequent read operations, then it might just be better to use a different approach or just set that key to undefined
manually.
Top comments (0)