Q: Where Does JavaScript Go?

The Web is ever changing, and this article is relatively ancient having been published 13 years ago. It is likely out of date or even blatantly incorrect in relation to modern better practices, so proceed at your own risk.

A: The bottom of your page, just before the </body> tag is your safest bet. Of course, with Web development, nothing is as easy as a blanket statement like that, right? But, when I’m helping people troubleshoot their JavaScript problems, 95% of the time the first step is to move the JS to the bottom, order the scripts properly and wrap it in some sort of function that starts only after the page is loaded. This not only fixes their problem, but often speeds up content loading. Read on to learn why this is a good rule.

You can’t affect an element that doesn’t yet exist

When attaching events to an object (one of the most often used JavaScript things I see), that object must exist to have an event attached. When you have a bit of script at the top of the page, it is run as soon as the script appears, meaning the object you’re trying to attach the event listener to doesn’t exist. For starters, the DOM, which is the structure that allows you to interact with elements in your page, has not finished loading at this point, nor have your elements inside of the <body>.

If your script is at the bottom, however, even if the DOM isn’t complete, chances are good that your element will at least exist on the page, able to be manipulated. That’s why nothing is happening when your code in the <head> is trying to set up some cool thing to happen when you click an object; the object didn’t “hear” you tell it to do that cool thing—it was in rendering limbo, outside the realm of your script’s reach.

Waiting for the DOM to be ready

Simply moving the code to the bottom doesn’t necessarily mean everything will be loaded, however. The best practice is to explicitly tell your code not to run until either the body is loaded (for older browsers), or until the DOM is ready (for modern browsers). I can’t explain how to do this in every library that exists, because I haven’t used them all (check out their documentation), and that’d make for a very long article, but in jQuery, it can be done with this code:

$(document).ready(function() {      ... all your code here ...    });

Or the shorthand version that looks like:

$(function(){    ... all your code here ...   });

However, if you’re manipulating images, you’ll need to wait until those are downloaded as well. That’s not necessarily done before the DOM says it’s ready. In that situation, you would wrap your code with:

$(window).load(function() {  ... your code ... });

The above is triggered after every piece of the document has been downloaded, including all of your images.

In plain-Jane non-libraried JavaScript, you’d be using something along the lines of

window.onload = function(){  ... your code ... });

This is the essentially the same as the method of <body onload="some code goes here">, which should not be used because you should be separating your function from content. Using window.onload allows you to have your code in a separate file, easily included or changed in multiple documents.

Does any one know how to check if the DOM is ready with plain JavaScript? Forgive me, but the process escapes me at the moment.

On the subject of page speed

Now, a slow-loading page isn’t necessarily a broken page, although some research shows that visitors will quickly bounce if they have to wait too long for the page to load. But page speed can often be improved, and many times it’s hanging because of scripts in the <head>. Most pages consist of a multitude of files in addition to the basic page: CSS, JavaScript, images, etc. To speed up loading times, browsers will try to download these in parallel—multiple files at the same time. JavaScript, however, is not pulled down in parallel. So, once a JavaScript file download starts, everything else is put on hold until the script finishes. If the JavaScript is in the <head> of your document, this means your users are starting at a blank screen while the script finishes. If your JavaScript is at the bottom of the page, your content loads first. Your well-written, interesting content should keep visitors busy while the rest of the scripts finish loading.

How I roll

I use the following order for setting up my scripts at the bottom of the page. I’ve found that it provides the best results for my uses both here on my personal site and on sites I develop for others.

  1. JS Library (usually jQuery)
  2. Plug-ins, if any (such as Lightbox, SimpleModal)
  3. My site-specific code (usually invoking plug-ins, form validation, etc)
  4. Social media plug-in (AddThis)
  5. Tracking code

You can view the source of this page to see all of that code at the bottom. (Or don’t, I really need to clean it up! I’m causing you to load the contact form validation even when there is no form. That’s very naughty of me, and I promise to fix it post haste.) The exceptions are ads and the custom search script which both appear at the point in the code where they show on the page, due to requirements of the code and companies.

When should you not place it at the bottom?

When making such a generalized statement like “at the bottom,” there are going to be exceptions. The number one exception to placing the code at the very bottom of the page is: when the provided documentation, manual, or instructions say otherwise. Now, I rarely come across such instructions except for in outdated code that shouldn’t be used anyhow*. One notable exception is SWFObject, a wonderful script for use with Flash on a page. They say put the code in the <head>. I haven’t done enough testing to say that it’ll work with the script at the bottom, so <head> it is.

The other exceptions I see regularly are ads and widgets. Ad servers, such as Google AdSense, are usually structured so that you place the scripts wherever you want the ad to appear. Unfortunately, these slow down your page load, but there’s nothing to be done until they improve their scripts. Likewise, some widgets require placement at the point in the code where they should appear rather than at the bottom of the page. Try to find alternatives if possible, otherwise, do as the documentation instructs.

A final note, speaking of code that’s supposed to go in the <head> element…: please, please, for the love of all things sacred do not use MM_Preload or MM_Menu or any other old Dreamweaver/Fireworks JavaScript that is prefixed by “MM.” Without exception, I have never seen this code do anything that cannot be accomplished in a better way, often without the use of JavaScript to begin with. </rant>

Do you have any other quick JS debugging tips? Has this strategy fixed your JS issues?

6 thoughts on “Q: Where Does JavaScript Go?”

  1. Awesome article again!! The Google PageSpeed tool hates my website :(

    I'm going to try moving the Javascript around based on what you've said here to see if I can improve the bounce rate on my website and the page loading time.

  2. When attaching events to an object (one of the most often used Javascript things I see), that object must exist to have an event attached.

    Not necessarily, or rather it's not a good idea to attach events directly to objects. Every time you attach an event to an object that's a performance hit. On smaller pages, maybe that's not a big deal, but lets say you are on a "view all" page of an e-commerce site. You don't want to go and attach one or more event listeners to every single product.

    Instead, use event delegation by attaching the event listening to the document and then waiting for the even to "bubble up." When you click a link, that event is also registered on the document, so listen once for the event on the document and then use some simple logic to determine which specific object the event came from and what to do with it.

    jQuery makes this supper easy with their .live() method which handles all that event delegation for you. The 1.4.2 release also comes with a .delegate() method that lets you specify the parent element to delegate the event listening to if you don't want to use the document object.

    An added affect besides awesome performance is that the objects you are listening to no longer need to exist to register the event listener, since you are binding it to the document, rather than the objects themselves. Thus you can use this along with AJAX and other dynamic content methods to insert new objects onto a page and not have to worry about listening for them specifically, as your delegated listening is already taking care of it.

    Another fun javascript performance tip is to concatenate and minify your script files. When you minify them you strip out excess text like extra whitespace and comments reducing the file size for a faster download. Concatenating the files combines the javascript all together so rather than downloading a library file, four or five plugins and a file for the site code, the user has to wait for only a single file to download with only a single HTTP request.

  3. Kandi, let me know how that works out for you. Hope you find a solution to cache problems, too.


    Valid point about the event delegation, Adam. I should have phrased that better. Optimization and performance are very important, and yes, concatenation and minifying (and going further gzipping). And fewer HTTP requests is always a win.

    Unfortunately, when you’re working with someone else’s plugin, you have no guarantee that they’re properly utilizing event delegation techniques, nor does most documentation explain the technique, so for the beginner trying to hack together a workable site, the best thing to do is wait for load to mitigate issues with non-existent elements.

  4. Fair enough. Thanks for fixing up the markup in my comment, I keep forgetting all the tags get stripped out of it. But back to your original point, every time I include javascript at the bottom of the page I kinda feel dirty. It just seems like they should go in the head, but then there's all that performance complications. I just wish modern browsers would accept the "defer" attribute on script tags so that the rest of the page's content can download before the javascript does…

    1. Ah yes, the defer attribute. I almost forgot about its existence. I wonder why browsers stopped supporting it (or is it that they never started? I don't recall it ever working).

      And I did fix the comment code at least to the point where your line breaks will stay in now. I get spammed too much to allow code at this point in comments. I'm working on starting to allow some basic formatting tags.

      1. Defer supposedly works in IE, and has for some time, but no other browser has ever implemented it, except for the ancient Netscape 3 and 4.

        If you have problems with spam, perhaps implementing something like markdown (http://daringfireball.net/projects/markdown/) could work rather than allowing direct HTML input. There's PHP versions out there, so don't worry that the original was in PERL.

        That said, I've found that two simple steps help with SPAM. The first is to have a hidden empty field, and check on comment submission that it stays empty. SPAM bots tend to check your comment form and fill everything out, so if there is ever content there, you know it is from SPAM and not humans. The second option is on submission check the referring URL to make sure it is from your site. It's not like SPAM bots actually fill in your form and submit it, they just check the inputs and send a get or post request directly. So if there is no referring URL, its a SPAM bot.

        Though the method I think I'm going to implement for my own site, if I ever actually get around to it, is rather than just having an open form, I'm gonna require authentication via Twitter login or Facebook connect.

Comments are closed.