I made a graph about js runtimes at 2am / by Becca Barton

The best time to code is at 1am, and the best time to analyze that code is 2am. — ancient proverb, me, 2:30am last night

Some background: Y’day at work I found myself working on a data migration in a node app, and in need of a way to check if an item is in a list of pre-gathered ids. We were in a unique position of being able to put this list of ids into any form we want, because we’re the boss, and since we’d just be storing it into a file and importing it into the migration. I’d started with putting the data in an array, and accessing with .includes(), but since we’d have to do this check on a gigantic amount of items, I wondered if there was opportunity to speed up this check a little bit.

My suspicion was that maybe turning it into an object and calling object[key] would be a better solution, since that can be accessed in linear time, right? And array access methods would vary more wildly since sometimes it has to look through the whole array, or halfway, or maybe its in the beginning, etc

you thought!!

Anyway I ended up deciding to make a graph to track a few ways to access and get an average of their times bc assuming isnt the same as… knowing. I will now describe to you my methodology and what I tested because I am, above all else, a scientist. (please do not ask me about my degree).

Access methods tested

  • Data in an array, accessed with .includes()

  • Data in an array, accessed with .indexOf()

  • Data in an object, accessed with object[key]

  • Data in an object, accessed with .hasOwnProperty()

  • Data in a set, accessed with .has()

What did that data look like

Array —> [‘longid1’, ‘longid2’, ‘longid3’]
Object —> {‘longid1’: true, ‘longid2’: true, ‘longid3’: true}
Set —> new Set([‘longid1’, ‘longid2’, ‘longid3’])

How the hell

To get the runtime of each, I used console.time() to get a sense of the runtime of each method. it looked something like this, and output a time in ms:

// Input
console.time("Test run array")
testArray.includes(idWereLookingFor)
console.timeEnd("Test run array")
// Output
Test run array: 0.022ms

Data gathered

I gathered 13 consecutive data points from the middle of the loop, and then let each method run 3 times, and averaged each time together (ie: (1st runtime of 1st test in ms + 1st runtime of 2nd test + 1st runtime of 3rd test) / 3) to account for some variance bc computers, like the wind, can be unpredictable.

…and now I present to you the graph:

13 consecutive results from middle of a loop (avg of 3 runtimes)

Analysis

Is this a large enough data set to come to real life conclusions? No! But it’s an interesting look at these various methods to see what patterns might develop.

Putting on my scientist’s lens, I can conclusively say, based on the results of this graph, that indexOf() sucks. hasOwnProperty honestly shocked me here. It was a late edition to the experiment but it ended up winning the trophy. Overall, it’s nice to see some of the ideas I had validated: object[key], for the most part, was pretty consistent in access time, and it was usually faster per run than array access methods. However, set and object.hasOwnProperty may have varied more per run, but overall were pretty consistently the fastest.

Ultimately we ended up going a different route with the migration that meant we didn’t need to do an id check at all, but had I needed to choose one of these methods, I would have gone with either hasOwnProperty() or set. I think I’d favor set here because in this case, we really don’t care about anything besides knowing if the current id exists within the list of ids, and set would allow us to have an unordered, unindexed list where we wouldn’t need to save an unnecessary value.