Yahoo! Developer Network Blog
« Previous | Main | Next »
July 12, 2007
High Performance Web Sites: Rule 6 – Move Scripts to the Bottom
Rule 5 described how stylesheets near the bottom of the page prohibit progressive rendering, and how moving them to the document HEAD eliminates the problem. Scripts (external JavaScript files) pose a similar problem, but the solution is just the opposite: it’s better to move scripts from the top to as low in the page as possible. One reason is to enable progressive rendering, but another is to achieve greater download parallelization.
With stylesheets, progressive rendering is blocked until all stylesheets have been downloaded. That’s why it’s best to move stylesheets to the document HEAD, so they get downloaded first and rendering isn’t blocked. With scripts, progressive rendering is blocked for all content below the script. Moving scripts as low in the page as possible means there's more content above the script that is rendered sooner.
The second problem caused by scripts is blocking parallel downloads. The HTTP/1.1 specification suggests that browsers download no more than two components in parallel per hostname. If you serve your images from multiple hostnames, you can get more than two downloads to occur in parallel. (I've gotten Internet Explorer to download over 100 images in parallel.) While a script is downloading, however, the browser won’t start any other downloads, even on different hostnames.
In some situations it’s not easy to move scripts to the bottom. If, for example, the script uses document.write to insert part of the page’s content, it can’t be moved lower in the page. There might also be scoping issues. In many cases, there are ways to workaround these situations.
An alternative suggestion that often comes up is to use deferred scripts. The DEFER attribute indicates that the script does not contain document.write, and is a clue to browsers that they can continue rendering. Unfortunately, Firefox doesn't support the DEFER attribute. In Internet Explorer, the script may be deferred, but not as much as desired. If a script can be deferred, it can also be moved to the bottom of the page. That will make your web pages load faster.
Steve Souders
[Steve Souders is Yahoo!'s Chief Performance Yahoo!. This is one in a series of Best Practices for Speeding Up Your Web Site. This article is based on Steve's book High Performance Web Sites, published by O'Reilly.]
Posted at July 12, 2007 5:04 PM | Permalink
Comments
How do things like onload and using YUI events to trigger scripts on load affect this?
Posted by: Scott at July 12, 2007 12:16 AM
The onload event won't fire until all scripts are downloaded, so if you move your SCRIPT tag lower in the page, you'll still be guaranteed that it's loaded _before_ the onload event.
Posted by: Steve Souders at July 12, 2007 12:27 AM
Sorry, the comment system stripped out my html in the previous comment. Resending:
Very good to know. Thanks! One more question :) I assume the best place to put the scripts are right before the BODY tag, right? Are there any common reasons (I am sure there are exception cases) where scripts MUST be put in the HEAD section and wouldn't work at the end of the BODY section?
Thanks for this tip. I have been annoyed by some slow load times on some pages and this tip + the tip about HTTP headers and expiry times hs been very useful.
Posted by: Scott at July 12, 2007 12:00 PM
You don't need to put scripts in the HEAD. You can put them right before the close BODY tag.
Posted by: Steve Souders at July 12, 2007 12:33 PM
Great post. Too often web developers neglect simple techniques like this. It's great to see that some don't. Thanks for posting!
Posted by: Stephen at July 12, 2007 8:52 PM
There is a simple solution I can think of that would meet in the middle ground. You could include your javascript in the html document, not as an external dependency. If you have a short javascript function, it would actually load much faster not having to deal with the overhead of requesting a separate download. Even if your js function needs to be in the header, what's 1kB, even to a 56k modem?
Posted by: Chris at July 17, 2007 10:13 PM
What about loading the scripts once the document has loaded ? Some libraries already do this (scriptaculous I think) and I assume it improves loading times because only one small script is loaded, and the remaining javascript files load when the document has finished loading.
Posted by: David at July 21, 2007 5:47 AM
Yes, the "post-onload download" technique is a great idea if the script is not needed for rendering the page. In Rule 8 - Make JavaScript and CSS External I mention combining inlining with post-onload download. This is definitely a great way to speed up your pages.
Posted by: Steve Souders at July 21, 2007 9:29 AM
External scripts will be downloaded before the onLoad event fires, but what about for YUI's own onDOMReady event? I find this event to be much more useful than onLoad.
@Chris: You have to be careful with internal Javascript. Besides losing some of the obvious advantages of external scripts like separated development concerns, reusable code and browser caching, performance for a page can actually turn out worse than before. Just the other day I tried pasting the contents of 5 or 6 CSS and Javascript files into html (using velocity's #include directive), figuring that the page would load faster since it's the same amount of data, but over fewer requests. Instead, the loading time for the html seemed to double what the total loading time was when those files were separate requests. I'm a bit mystified. The only thing I can think of is that Firefox was downloading those in parallel, even though they appeared to be staggered in Firebug. Any thoughts/suggestions?
Posted by: Josh Singer at July 25, 2007 10:29 AM
I am using YUI in a few places of an application I am building. In some cases, I have not been able to put the script references at the bottom of the page. The best example is where I am using the Menu component and am generating my menu from existing markup. If I include the YUI script references at the bottom, there is a (small) period of time where my menu markup renders in HTML before YUI takes over and cleans it up.
Of course, the workaround is to make the YUI menu generate from JavaScript, but I just wanted to point that out.
Outside of the situation where YUI performs actions against existing markup, I am able to put my JS at the bottom.
Posted by: Scott at July 25, 2007 2:58 PM
What about web standards. Don't SCRIPT elements have to appear in the head of a document?
Posted by: Jack at August 2, 2007 8:15 AM
Looks like this point is annoying. I'm overruling the rule 'minalize js', but i use this rule too. When dealing with a total amount of .. 6-7 rules of javascript code, when shifting all scripts to the bottom, i found that scripts that used too be quik, now have some form of LAGG.
Any ideas on this? :P
Posted by: J. de Boer at August 19, 2007 8:53 AM
Yes, this rule is definitely confusing. I get a lot of questions about this one.
Let's first tackle external .js scripts that aren't needed for rendering the page. For example, suppose you have a DHTML feature that is unlikely to be exercised until after the page loads and renders. For these external scripts, post-onload download is the best solution.
If you have JS code that is part of rendering the page, like setting focus or drawing a tree, then I recommend moving the external script in the HTML document to be placed right above these HTML elements. That way, any resources and text above these scripts can be downloaded and rendered without blocking.
If your situation doesn't fit into one of these, it's safest to put them in the HEAD.
Posted by: Steve Souders at August 20, 2007 1:51 PM
I too am concerned about script tags not allowed outside the head.
Posted by: UI Engineer at August 24, 2007 5:50 PM
To the people about script tags outside the head, have a look at the HTML DTD:
http://www.w3.org/TR/1999/REC-html401-19991224/sgml/dtd.html
script is allowed:
* directly inside the body
* directly inside blockquote
* directly inside form
* directly inside head (of course)
* within any inline, which includes: span, sub, sup, %flow, address, a, p, ... the list goes on.
Posted by: Jeremy Dunck at August 28, 2007 9:44 PM
@Jeremy Dunck
And what about XHTML strict?
Posted by: Xscratch at September 5, 2007 6:18 AM
From http://www.quirksmode.org/js/placejs.html:
Generally you place JavaScripts in the of a page. Only when you want to write a message in the page, you'll have to place the script in the correct place in the HTML.
Placing scripts in the makes sure that any functions are loaded before the buttons, links or other things that call them are loaded. If you put your scripts at the very end of a page, it is possible that a user already sees part of the page including a button with a JavaScript function call, while the rest of the page hasn't loaded yet. Result: user pushes button and gets JavaScript Error Message Alerts, because the browser can't find the script (yet).
Unless there's a good reason to do otherwise, place your scripts in the
-----------------------------------------------
I have seen this where users that click on an element that has "onclick" defined before the function has time to load will get errors which end up breaking the functionality completely. If you are going to put js at the end of the file how best do you determine that these user driven events have the code that they need? Perhaps what is needed is a wrapper function which you load in the header which checks to see if the function you really want exists and if not do a setTimeout to try again later. What are people's thoughts on this?
Posted by: James Irwin at October 4, 2007 5:14 PM
In the HTML document define a "stub" function that is tied to the element in the page. That way, even if the external script has not been downloaded, the user won't get any JS errors. Then when the script is downloaded, the new function definition will override the empty one. You can see this in My Yahoo, for example. Notice functions like
function ycsp_do_menu(){return true;}
That are redefined in a later script.
Posted by: Steve Souders at October 8, 2007 10:38 PM
@Xscratch: I think the best is to attach the onclick events using javascript executed on domready. This way the user will find ordinary html elements that doesn't spout out errors before domready has fired.
Posted by: Motin at October 22, 2007 5:15 PM
Steve, your new High Performance book is amazing. Thanks so much for writing it.
As for moving Prototype/Script.aculo.us to the bottom of the page, it's impossible because, for whatever reasons, certain javascript libraries are not being parsed and have to be included before (in the html) any usage of said library is used.
Eg, if I include the libraries at the bottom of the page and I do (function (){Effect.BlindUp($('div_id'));}).delay(5), the browser spits out some type of error regarding that function is unknown.
More specifically: "Error: (function () {Effect.Fade($("error_bulletin"));}).delay is not a function". However, if I move the js libraries back up to the top, it works perfectly fine.
Posted by: Don Wilson at November 6, 2007 1:28 PM
Hi, Don.
Thanks for the feedback on the book. It makes those 10 months of late nights worth it!
Yes, you can't move a script to the bottom if it's symbols are referred to above. You could move the script higher in the page (not great) or find a way to call the desired code _after_ the script is download (eg, onload handler).
Posted by: Steve Souders at November 6, 2007 2:12 PM
Where to place style elements?
I'm surprised that anyone has to recommend putting style sheets in the head - that is the *only* place they are allowed in valid HTML.
Posted by: RobG at November 13, 2007 9:19 PM
While I didn't notice any performance gain by moving scripts to the bottom of the document (may be because i'm on localhost), I did notice an issue with this method. I use ondomready to add a few classes to the body such as "jsEnabled browser-(ie|gecko|webkit)" and so on. I have different CSS rules for the different classes, i'm sure you guys know about this technique. Anyways, on IE, when the page gets loaded, there's a "style change flicker" as the new style takes effects after my code added the class names to the body. For example, if I have the following css rules:
/* default width */
#container {
width: 100px;
}
/* say you want to increase the width on IE */
body.browser-ie #container {
width: 200px;
}
when the page gets loaded, I notice that the #container element quickly changes its width. This is on localhost and using domready so there isn't any other latency factors. This is only noticeable on IE(7). Anyone else notice this?
Posted by: Tuan at November 15, 2007 1:05 AM
Just regarding the Web Standards and script lement positioning in XHTML documents, script elements are allowed in either the Head OR the Body, as you like, according to this reference:
http://www.w3.org/TR/2003/WD-xhtml2-20030506/mod-scripting.html#edef_scripting_script
Posted by: Phil GRAHAM at November 17, 2007 7:27 AM
I did a source lookup on this page and found a script tag between and . That seems to be a really weird place to place a script tag.
It will be nice if there is any recommendation on where exactly to place the script, in a cross browser safe, standards compliant way.
On this note I would also like to thank the Yslow team for having built such an awesome tool - I use it all the time!
Posted by: Ajay at December 17, 2007 9:35 AM
There are some cases where you wouldn't want your JS at the bottom. For example, if you were using an "ondomready" event that many of the js libraries supply, you would want the code to execute towards the top. If you were to move all your JS to the bottom of the page, the event would be rendered useless.
However, it's nice to know that having it at the top is a performance hit so that I can weigh the positives with the negatives before moving forward.
Posted by: rob at February 6, 2008 7:56 AM
The yahoo mail Beta is heavy on javascript, and they don't go by this rule. I suppose they should..
Posted by: alex at February 6, 2008 11:11 AM
OK.. so the javascript which doesn't contain document.write etc can be moved to the bottom safely. But which is the safest place? Is it just before ending form tag, or before ending the body tag, or before ending the html tag or after closing the html tag? Plz give your valuable suggestions which might help others as well as for me.
Posted by: Vijay Karla at June 28, 2008 12:50 AM
I use jquery primarily. I want my pages clean of inline scripting as possible. I also want my external file references in the header. It makes sense to me that the functionality of the page be in place before the activation objects (such as buttons to click on) are loaded afterwards.
If you intend to create websites, its my opinion javascript should only enhance the page, not make it functional. So as an example, the page with javascript turned off should still be functional, thus preventing the most of the problems mentioned above.
My 2 cents.
Posted by: brandonrichards at August 15, 2008 2:08 PM
This is a very useful method for making a site appear to load faster than it actually is. If you are using good, unobtrusive JavaScript techniques (and making JS enhance the site rather than create it) this is a beautiful technique.
Most of the negatives in these comments are stemmed from bad JS practices - body onload attributes and document.write (:x) should not be used in the new web world we live in.
All modern JS libraries make use of a document.ready event, which is key producing JavaScript that only gets activated when the site is done loading. In this scenario, the script tags are fine to have right before the closing body tag - it makes the visible parts of the screen load first, and once the js is loaded and the dom is ready - the javascript fun kicks in and it's a fun user experience for all.
Posted by: Jade Rauenzahn at August 22, 2008 8:04 AM
In my opinion it's best to keep the main javascript file in the head of your document. I use an ajax method to request all of my javascript files. This makes sure they start loading right after (in my case) jquery.js is loaded and don't queue up other items on the page.
I prefer this technique over the "move to bottom" one due to two reasons:
1. Your JS files get loaded at the start which _usually_ means they are done by the time the page ie done loading.
2. You are less likely to get into any kind of problems due to your javascript not being loaded in the head of the document
Too bad YUI doesn't detect these kind of techniques as it gives me an F for still loading in the head ;)
Posted by: Jean at September 17, 2008 12:37 PM
I moved my scripts to the bottom of the page, just above the . I cleared cache. I reloaded the page and YSlow is still giving me an "F" for scripts not loading at the bottom. Any idea why?
Posted by: Chris Hiester at December 31, 2008 9:54 AM
I find it very difficult to match this rule on heav javascript sites:
In some situations, even onDomReady is not enough, and it is nicer to use something like onElementAvailable or use inline script blocks below the element concerned (e.g. a complex ajax form). Otherwise, your event handlers might be attached too late and thus a user with javascript turned on might get the unenhanced version.
If my main scripts are minified and gzipped I rather put them in the head, to make sure they are available as soon as the page starts rendering - even if this gives me an F :)
Posted by: Andreas Stephan at February 19, 2009 10:24 AM
I don´t agree with this rule. This is not a rule. Cases where the script doesnt affect the interation like Google Analitics, it's absolutely convenient. But when you have ajax interactions, you put script in the bottom and when the pages came up he interacts with it without have loading yet the page.
Posted by: Alexandre Magno at March 14, 2009 10:54 AM
is this rule is saying- that we need to place JS file in bottom like this way?
pls suggest me?
Posted by: prashant at May 21, 2009 4:55 PM
OK, so I've done all the work of moving inline script blocks to the bottom of the page and not referencing any library specific functions until after library has loaded. These are all sensible changes which make the page faster.
Now here's where it gets insensible. At my day job we wrestle with lots of third party code. A couple of those integrations require code within the head.
Here's the question: to maximize parallel downloading of multiple stylesheets, should the script block appear before or after the style sheets in the head?
Posted by: Nils T. Devien at September 25, 2009 10:32 AM
What does 'Move scripts to the bottom' mean? Still inside head, or inside body, or after the closure of html element? I keep the js files inside the head for all my pages as before but YSlow give me A. It makes me confused about the word 'bottom'.
Grade A on Put JavaScript at bottom
There is 1 Javacript script found in the head of the document
Posted by: Tonado at October 29, 2009 11:28 PM
Post a comment
Comment Policy: We encourage comments and look forward to hearing from you. Please note that Yahoo! may, in our sole discretion, remove comments if they are off topic, inappropriate, or otherwise violate our Terms of Service. Fields marked with asterisk '*' are required.
Subscribe
Recent Blog Articles
view all
YQL Open Table for Google Buzz now live
Tue, 09 Feb 2010
INSERT INTO twitter.status ...
Mon, 08 Feb 2010
Announcing the Yahoo! Brasil Open Hack Day 2010, 20-21 March
Mon, 08 Feb 2010
Marketing hacks, linchpins, and tech women of valor
Sun, 07 Feb 2010
Yahoo! India invites you to join the first India Hadoop Summit
Thu, 04 Feb 2010
Recent Links
Appcelerator Titanium + Yahoo YQL on Vimeo
Mon, 08 Feb 2010
Tue, 02 Feb 2010
PhoneGap | Cross platform mobile framework
Sat, 30 Jan 2010
Web developers can rule the iPad - O'Reilly Radar
Sat, 30 Jan 2010
rc3.org - Is the iPad the harbinger of doom for personal computing?
Thu, 28 Jan 2010
Archives
2010
2009
2008
2007
2006
2005
Recent Readers

