Is there a faster solution than document.getElementById()?

JavaScript should be written on a computer. That goes without saying. But in 2011, during my final post-secondary exam, I had to write JavaScript functions out by hand.

Yes, I physically had to write out loops, variables, selectors, and even:

document.getElementById();

And I loathed writing it. It used up so much space on my paper. I’m not even kidding. Go write it out. JavaScript functions should never be written on paper.

Actual picture of me, having to write document.getElementById() out by hand

Instead, I made something like this:

function getId(id) {
return document.getElementById(id);
}

And if I needed it, I just called getId(). I also made one for getClass() because I’m a nerd.

A year later I learned jQuery and now my getId() function had become:

jQuery('#id');

The fact that I could also use CSS selectors blew my mind. I could do stuff like this:

jQuery('.list:first-child ~ li[icon*="fa-"]'); 

and it worked! jQuery opened up so many possibilities!

But that was in 2011. Now it is 2021. People still use jQuery all the time, but it’s like a shadowy black art now. Oh, uh, jQuery? Yeah, just do this… But why not use Vanilla.jsinstead? It performs much better.

And that’s fair. Thanks to things like document.querySelector() and document.querySelectorAll() we can now use CSS selectors in vanilla JavaScript. You can even use document.querySelector() to replace document.getElementById() if you wanted. The difference is that the former runs at 15 million calls a second and the latter runs at 7 million calls second.

Which, granted, are both very fast.

But what if there was a faster way? One that didn’t involve document.getElementById()? One that, if my teacher had done their job in post-secondary, I didn’t even need to make getId() ?

Well, there is.

Please, consider the following:

<div id="myElement"><div><script>
console.log(myElement);
</script>

When you create an HTML element using an ID, a global namespace is already made. There is no reason to use document.getElementById() at all. I know, it’s super cool. But there are a few downsides.

First off, it’s “bad practice”. It’s a relic from before the Browser Wars and while it’s still supported today, it isn’t recommended. A few docs I’ve read said it can also lead to “brittle code”, which makes “brittle” sense (ha) because if you add this line:

var myElement = 'whatever';

You lose access to your global variable. But that’s the same for literally anything with JavaScript. If you do this:

var overwritable = 'whatever';
var overwritable = 'whatever yourself';
console.log(overwritable);

It logs whatever yourself . So this isn’t any more brittle than JavaScript already is.

There is also the issue that some people are monsters and use hyphens instead of camelCase (or, idk, underscores?) when IDing their elements. A JavaScript variable name can’t have a hyphen in it, so this would break.

But we will deal with that issue in a moment.

If you actually test the speed between these two:

<div id="myElement"></div>
<div id="myElement2"></div>
<script>var a = performance.now();
console.log(myElement);
var b = performance.now();
var c = performance.now();
console.log(document.getElementById('myElement2'));
var d = performance.now();
console.log("Global call took " + (b - a) + " milliseconds.");
console.log("By Id call took " + (d - c) + " milliseconds.");
</script>

You will see that document.getElementById() performed at about 2x the speed. So, the global variable isn’t faster.

But…

The reason for this is because accessing global variables is slow. It needs to parse the window object, find the value and then return it. So what if we don’t make it global? What if we make it local instead?

const fasterMyPrecious = myElement;

And we choose const because we don't want “brittle code” or whatever so it can’t be overwritten. This also solved the hyphen issue since we have to name our local variable.

So how does it perform now? Well, it varies between every call by ±0.01 milliseconds each time the script is run, so if we put it in a loop and run it 1000 times, we get:

Global call took 88.68000004440546 milliseconds.
By Id call took 92.66000072238967 milliseconds.

“But that’s not fair!” you cry. “ fasterMyPrecious is cached, while document.getElementById() is not.”

“Fine,” I reply. “Then let’s cache them both.”

With our current working script being the following:

<div id="myElement"></div>
<div id="myElement2"></div>
<script>const fasterMyPrecious = myElement;
const cachedById = document.getElementById('myElement2');
var a, b, c, d;
a = b = c = d = 0;
console.log('start');for (var i = 0; i < 1000; i++) {var a = performance.now();
console.log(fasterMyPrecious);
var b = performance.now();
var c = performance.now();
console.log(cachedById);
var d = performance.now();
}console.log("Global call took " + (b - a) + " milliseconds.");
console.log("By Id call took " + (d - c) + " milliseconds.");
</script>

The results are:

Global call took 88.55000001494773 milliseconds.
By Id call took 91.63999947486445 milliseconds.

But here’s the Horcrux to the whole thing. If we flip the script and put the cachedByIdabove fasterMyPrecious:

<div id="myElement"></div>
<div id="myElement2"></div>
<script>const fasterMyPrecious = myElement;
const cachedById = document.getElementById('myElement2');
var a, b, c, d;
a = b = c = d = 0;
console.log('start');for (var i = 0; i < 1000; i++) {//now above
var c = performance.now();
console.log(cachedById);
var d = performance.now();
//now below
var a = performance.now();
console.log(fasterMyPrecious);
var b = performance.now();
}console.log("Global call took " + (b - a) + " milliseconds.");
console.log("By Id call took " + (d - c) + " milliseconds.");
</script>

They print out with cachedById (aka document.getElementById ) being faster.

Global call took 92.1750005800277 milliseconds.
By Id call took 89.70999921439216 milliseconds.

Okay, okay, okay. But what if we run them independently of each other? Then we get the following:

By Id call took 93.04500030702911 milliseconds.
Global call took 86.50500001385808 milliseconds.

With fasterByPrecious (aka the global namespace selector) being 6.54000029317 milliseconds faster.

Granted, this minor difference can be attributed to literally anything. Even a network ping can knock that off. So, I did the unthinkable and I disconnected my Internet (since you don’t need the Internet to run JavaScript) and ran it again:

By Id call took 98.13499977462925 milliseconds.
Global call took 94.89000029861927 milliseconds.

And fasterMyPrecious is once again the champion.

In summary, while there is a faster solution than document.getElementById() I’m really not sure what you’ll do with all that free time.

I am a web developer turned travel blogger that is forced to code to eat.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store