The art and craft of postload preloads

What can your tired old page, once loaded and used and read, can do for your user? It can preload components needed by the next page, so when the users visit the next page, they have the new scripts, styles and images already in the cache. Next page loads faster and the user's happy. On its death bed you tired old page has left a good inheritance for future generations. Good old page.

How can you go about preloading for the next page? By waiting for onload of the current page and requesting the new components. Here are 4 ways to do so, all using a timeout of 1 second after page load so that prefetching doesn't interfere with the user experience on the page.

One way... (DOM)

Using DOM you can create a new LINK element and a new SCRIPT element and append them to the HEAD. For images - it's a one-liner new Image.src="..."

The drawback of this method is that your CSS is executed against the current page and might affect display. Same for JavaScript - it's executed. The image is simply requested and never displayed.

window.onload = function() {
    setTimeout(function(){

        // reference to <head>
        var head = document.getElementsByTagName('head')[0];

        // a new CSS
        var css = document.createElement('link');
        css.type = "text/css";
        css.rel = "stylesheet";
        css.href = "new.css";

        // a new JS
        var js = document.createElement("script");
        js.type = "text/javascript";
        js.src = "new.js";

        // preload JS and CSS
        head.appendChild(css);
        head.appendChild(js);

        // preload image
        new Image().src = "new.png";

    }, 1000);
};

DOM test page

For this way of doing it you can use any JavaScript library's helper methods to load stuff on demand. Good examples - YUI Get and LazyLoad

... or another ... (using iframe)

Another option is to create an iframe and append your components to its head. Using an iframe you can avoid the CSS potentially affecting the current page. JavaScript will still be executed.

window.onload = function() {
    setTimeout(function(){

        // create new iframe
        var iframe = document.createElement('iframe');
        iframe.setAttribute("width", "0");
        iframe.setAttribute("height", "0");
        iframe.setAttribute("frameborder", "0");
        iframe.setAttribute("name", "preload");
        iframe.id = "preload";
        iframe.src = "about:blank";
        document.body.appendChild(iframe);

        // gymnastics to get reference to the iframe document
        iframe = document.all ? document.all.preload.contentWindow : window.frames.preload;
        var doc = iframe.document;
        doc.open(); doc.writeln("<html><body></body></html>"); doc.close(); 

        // create CSS
        var css = doc.createElement('link');
        css.type = "text/css";
        css.rel = "stylesheet";
        css.href = "new.css";

        // create JS
        var js = doc.createElement("script");
        js.type = "text/javascript";
        js.src = "new.js";

        // preload CSS and JS
        doc.body.appendChild(css);
        doc.body.appendChild(js);

        // preload IMG
        new Image().src = "new.png";

    }, 1000);
};

IFRAME test page

... I'm gonna find ya ... (static page in iframe)

If your components are static you can create a page that has them all and load that page into the dynamic iframe. Static means knowing them in advance, not relying on page's JavaScript to figure them out on the fly. As you can see, much simpler than the previous code.

window.onload = function() {
    setTimeout(function(){

        // create a new frame and point to the URL of the static
        // page that has all components to preload
        var iframe = document.createElement('iframe');
        iframe.setAttribute("width", "0");
        iframe.setAttribute("height", "0");
        iframe.setAttribute("frameborder", "0");
        iframe.src = "preloader.html";
        document.body.appendChild(iframe);

    }, 1000);
};

IFRAME static page test

... I'm gonna GETcha, GETcha, GETcha! (with Ajax)

Finally - Ajax. Scripts are not executed, CSS not used for rendering. Nice and clean. For simplicty the code has no support for browsers that don't know what XMLHttpRequest is.

window.onload = function() {
    setTimeout(function(){

        // XHR to request a JS and a CSS
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'new.js');
        xhr.send('');
        xhr = new XMLHttpRequest();
        xhr.open('GET', 'new.css');
        xhr.send('');

        // preload image
        new Image().src = "new.png";

    }, 1000);
};

Ajax test page

Thanks!

Any other ways you can think of?

This entry was posted on Thursday, August 27th, 2009 and is filed under Ajax, CSS, images, JavaScript, performance. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.


Get notification for future posts: follow me on Twitter or subscribe to my RSS feed

12 Responses to “The art and craft of postload preloads”

  1. Tech Thursday: Easy Git, preloading, books (including HTML5), accessibility news and SVG for IE | Techno Portal Says:

    [...] Stefanov has a great piece on postload preloads, which means preloading information needed by following pages on very popular [...]

  2. Dave Artz Says:

    Nice to have an article on this topic! Think it’s worth noting AJAX won’t work across domains, the scenario I live in.

    Have you tried something like this?

    new Image().src = ‘path/to/javascript.js’;
    new Image().src = ‘path/to/css.css’;

    …and seeing if that works?

  3. Stoyan Says:

    Hey Dave, good point for the ajax part. Using image to preload JS and CSS is not an option is FF, it has a separate cache for images and separate for JS/CSS.

  4. Twitter Trackbacks for The art and craft of postload preloads / phpied.com [phpied.com] on Topsy.com Says:

    [...] The art and craft of postload preloads / phpied.com http://www.phpied.com/the-art-and-craft-of-postload-preloads – view page – cached Stoyan’s blog about (x)html, ajax, bookmarklets, browsers, css, firebug, javascript, json, mdb2, mysql, pear, performance, php, phpbb, tools, yslow, yui, writing, music,… life and everything. — From the page [...]

  5. Dejan Kozina Says:

    Re: Method #1
    To avoid having the downloaded js executed you may try this:
    js.type = “text/html”;

    The browser would (well, should) download the script, do absolutely nothing with it bar for storing it in its cache and your next page will find the script already waiting in the cache…

  6. can u help me with this html doc plz: http://trucreation.net/band/doc.html? | Convert Word To Html Says:

    [...] The prowess and foxiness of postload preloads / phpied.com [...]

  7. HB Says:

    Never thought of XHRing to a script and not using/appending it. Does get cached though, very cool.

  8. dedektif Says:

    nice document, i liked method 1

  9. jpvincent Says:

    do we know if browsers cache XHR the same way than JS files ? (or even CSS)
    I mean : maybe that some have separate process to store XHR results and JS files so this technique might cache them twice ?

  10. Max Says:

    Well, if your gonna get the most out of XHR requests you need to go a little furthur than that by creating xhr requests objects per request, store them in an array and then reuse the objects once they are free’ed! This will maintain a good code standard.

    just my thoughts! =)

  11. Kyle Says:

    This is awesome.. love the color scheme and clarity here. Really simply/concise. Thanks!

  12. work at home Says:

    fiverr…

    [...]The art and craft of postload preloads / Stoyan’s phpied.com[...]…

Leave a Reply