This post is based on a chapter from Even Faster Web Sites, the follow-up to High Performance Web Sites. Posts in this series include: chapters and contributing authors, Splitting the Initial Payload, Loading Scripts Without Blocking, Coupling Asynchronous Scripts, Positioning Inline Scripts, Sharding Dominant Domains, Flushing the Document Early, Using Iframes Sparingly, and Simplifying CSS Selectors.
My first three chapters in Even Faster Web Sites (Splitting the Initial Payload, Loading Scripts Without Blocking, and Coupling Asynchronous Scripts), focus on external scripts. But inline scripts block downloads and rendering just like external scripts do. The Inline Scripts Block example contains two images with an inline script between them. The inline script takes five seconds to execute. Looking at the HTTP waterfall chart, we see that the second image (which occurs after the inline script) is blocked from downloading until the inline script finishes executing.

Inline scripts block rendering, just like external scripts, but are worse. External scripts only block the rendering of elements below them in the page. Inline scripts block the rendering of everything in the page. You can see this by loading the Inline Scripts Block example in a new window and count off the five seconds before anything is displayed.
Here are three strategies for avoiding, or at least mitigating, the blocking behavior of inline scripts.
- move inline scripts to the bottom of the page – Although this still blocks rendering, resources in the page aren’t blocked from downloading.
- use setTimeout to kick off long executing code – If you have a function that takes a long time to execute, launching it via setTimeout allows the page to render and resources to download without being blocked.
- use DEFER - In Internet Explorer and Firefox 3.1 or greater, adding the DEFER attribute to the inline SCRIPT tag avoids the blocking behavior of inline scripts.
It’s especially important to avoid placing inline scripts between a stylesheet and any other resources in the page. This will make it as if the stylesheet was blocking the resources that follow from downloading. The reason for this behavior is that all major browsers preserve the order of CSS and JavaScript. The stylesheet has to be fully downloaded, parsed, and applied before the inline script is executed. And the inline script must be executed before the remaining resources can be downloaded. Therefore, resources that follow a stylesheet and inline script are blocked from downloading.
It’s better to explain this with an example. Below is the HTTP waterfall chart for eBay.com. Normally, the stylesheets and the first script would be downloaded in parallel.1 But after the stylesheet, there’s an inline script (with just one line of code). This causes the external script to be blocked from downloading until the stylesheet is received.
This unnecessary blocking also happens on MSN, MySpace, and Wikipedia. The workaround is to move inline scripts above stylesheets or below other resources. This will increase parallel downloads resulting in a faster page.

Aaron Peters | 07-May-09 at 11:37 am | Permalink
Steve,
Again, strong article about something important, thanks.
I have question about DEFER.
The HTML 4.01 DTD states: “UA may defer execution of script.” The magic word here is of course ‘may’.
What are your experiences with IE7? Does IE7 always/often/sometimes/hardly ever actually defer the script execution?
- Aaron
Steve Souders | 07-May-09 at 1:32 pm | Permalink
Yes, IE does defer script execution. I go into more detail in the actual chapter, but you can investigate this more using Cuzillion. For example: this Cuzillion test page contains a two second inline script and a two second image, but the page loads in two seconds, showing that the script was deferred and executed while the image was downloading. You could add more resources and change the configuration settings to examine edge cases you have in mind.
Taimar | 08-May-09 at 1:42 am | Permalink
Are there cases where defer attribute can’t be used (some scripts won’t work etc) in inline but also in external scripts?
jkarczm | 11-May-09 at 3:34 am | Permalink
Taimar – you can use ‘defer’ when your scripts operates on DOM which you don’t know if it’s full loaded or not
jkarczm | 11-May-09 at 3:34 am | Permalink
sorry, “you CAN’T”
sunnybear | 15-May-09 at 10:04 am | Permalink
Steve, there is actually one more way to resolve huge timeout because of inline scripts execution. We can perform all critical calculations on the server and put on client only all final numbers (or final DOM tree).
tham | 18-May-09 at 12:20 am | Permalink
Hi,
I have a question.
document.getElementById(“applet”).innerHTML = ;
From the code above,,,is it possible that the race condition occurs between the declaration of the applet object and the onload event calling to the applet’s function????
I also want to know what is the sequence of execution when we have the onload event and the inline script in the body tag
Jeremy Dunck | 21-May-09 at 6:21 pm | Permalink
Steve,
I have a large body of HTML that I’d like crawlers to be able to see, but that same content will be styled into a nice carousel display when JS gets a chance to run. I am trying to minimize page jumping, so I can’t wait until the JS in the footer has a chance to run.
I was planning on using a very fast inline JS– just setting the carousel container size and overflow:auto– but now you’ve made me doubt the approach.
Do you have any suggestions on minimizing page jumping and keeping page content visible without JS, also while avoiding inline scripts? :-/
Nagaraj Hubli | 09-Jul-09 at 12:44 pm | Permalink
The best possible option is to move inline script to the bottom of the page, along with the DEFER attribute, right?