Positioning Inline Scripts

May 6, 2009 10:26 pm | 14 Comments

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.

Stylesheet followed by inline script blocks downloads on eBay
Stylesheet followed by inline script blocks downloads on eBay

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.

1All these resources are on the same domain, so downloading them all in parallel is possible on browsers that support more than two connections per server, including Internet Explorer 8, Firefox 3, Safari, Chrome, and Opera.

14 Responses to Positioning Inline Scripts

  1. 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

  2. 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.

  3. Are there cases where defer attribute can’t be used (some scripts won’t work etc) in inline but also in external scripts?

  4. Taimar – you can use ‘defer’ when your scripts operates on DOM which you don’t know if it’s full loaded or not

  5. sorry, “you CAN’T”

  6. 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).

  7. 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

  8. 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? :-/

  9. The best possible option is to move inline script to the bottom of the page, along with the DEFER attribute, right?

  10. In the 6th chapter of EFWS and in https://stevesouders.com/cuzillion/?ex=10100&title=Inline+Scripts+Block it’s mentioned that”Nothing in the page is rendered until the inline script is done executing.”

    The results i got when i tested this is:

    In IE8, Opera 10.51 & Firefox 3.6.3 the page is rendered till the inline script. The part after the inline script doesn’t get rendered until the inline script finishes execution.

    In Chrome 9.0.597.98 & Safari 4.0.5 nothing in the page is rendered until the inline script finishes execution.

    The format applied is:

    ….

    I couldn’t find the present status of browsers regarding inline scripts.

  11. In the 6th chapter of EFWS, the danger of CSS and inline script coming together is mentioned.

    The test page for this is:
    https://stevesouders.com/cuzillion/?ex=10103&title=Inline+Scripts+after

    The time taken in diff. browsers are:
    IE8 – 7436 ms
    Firefox 3.6.3 – 4860 ms
    Chrome 9.0.597 – 4748 ms
    Safari 4.0.5 – 4804 ms
    Opera 10.51 – 4952 ms

    I guess browsers other than IE8 starts downloading the external file when the inline script begins execution.

    Or is it some other reason that results in the less time in browsers other than IE8?

  12. there was a mistake in comment no. 10 https://stevesouders.com/blog/2009/05/06/positioning-inline-scripts/comment-page-1/#comment-3061

    If a page has an inline script, in Opera page is rendered till the location of the inline script. (tested in versions 10.51 & 11.01)

    In IE8, Firefox 3.6.3, Chrome 9.0.597.98 & Safari 4.0.5 nothing is rendered when the inline script is executing.

    Sorry for the mistake i made in the earlier comment

  13. @anish: It’s possible Opera behaves differently. It’s possible the other browsers have fixed the issue with inline scripts blocking stylesheets.

  14. Effect on downloading of resources when an inline script above it is being executed:

    IE8 – Will block downloading of image & iframe.
    Will allow downloading of stylesheet and .js file.
    http://www.webpagetest.org/result/110302_KG_30M6/

    IE9 – Will block downloading of iframe.
    Will allow downloading of image, stylesheet and .js files.
    http://www.webpagetest.org/result/110302_TN_30MS/

    Firefox 3.6.3, IE6, IE7, Chrome 10.0.648.127, Opera 11.01, Safari 4.0.5 – will block downloading of image, stylesheet and .js files.