Frontend SPOF

June 1, 2010 7:49 pm | 9 Comments

My evangelism of high performance web sites started off in the context of quality code and development best practices. It’s easy for a style of coding to permeate throughout a company. Developers switch teams. Code is copied and pasted (especially in the world of web development). If everyone is developing in a high performance way, that’s the style that will characterize how the company codes.

This argument of promoting development best practices gained traction in the engineering quarters of the companies I talked to, but performance improvements continued to get backburnered in favor of new features and content that appealed to the business side of the organization. Improving performance wasn’t considered as important as other changes. Everyone assumed users wanted new features and that’s what got the most attention.

It became clear to me that we needed to show a business case for web performance. That’s why the theme for Velocity 2009 was “the impact of performance on the bottom line”. Since then there have been numerous studies released that have shown that improving performance does improve the bottom line. As a result, I’m seeing the business side of many web companies becoming strong advocates for Web Performance Optimization.

But there are still occasions when I have a hard time convincing a team that focusing on web performance, specifically frontend performance, is important. Shaving off hundreds (or even thousands) of milliseconds just doesn’t seem worthwhile to them. That’s when I pull out the big guns and explain that loading scripts and stylesheets in the typical way creates a frontend single point of failure that can bring down the entire site.

Examples of Frontend SPOF

The thought that simply adding a script or stylesheet to your web page could make the entire site unavailable surprises many people. Rather than focusing on CSS mistakes and JavaScript errors, the key is to think about what happens when a resource request times out. With this clue, it’s easy to create a test case:

<html>
<head>
<script src="http://www.snippet.com/main.js" type="text/javascript">
  </script>
</head>
<body>
Here's my page!
</body>
</html>

This HTML page looks pretty normal, but if snippet.com is overloaded the entire page is blank waiting for main.js to return. This is true in all browsers.

Here are some examples of frontend single points of failure and the browsers they impact. You can click on the Frontend SPOF test links to see the actual test page.

Frontend SPOF test Chrome Firefox IE Opera Safari
External Script blank below blank below blank below blank below blank below
Stylesheet flash flash blank below flash blank below
inlined @font-face delayed flash flash flash delayed
Stylesheet with @font-face delayed flash totally blank* flash delayed
Script then @font-face delayed flash totally blank* flash delayed

* Internet Explorer 9 does not display a blank page, but does “flash” the element.

The failure cases are highlighted in red. Here are the four possible outcomes sorted from worst to best:

  • totally blank – Nothing in the page is rendered – the entire page is blank.
  • blank below – All the DOM elements below the resource in question are not rendered.
  • delayed – Text that uses the @font-face style is invisible until the font file arrives.
  • flash – DOM elements are rendered immediately, and then redrawn if necessary after the stylesheet or font has finished downloading.

Web Performance avoids SPOF

It turns out that there are web performance best practices that, in addition to making your pages faster, also avoid most of these frontend single points of failure. Let’s look at the tests one by one.

External Script 
All browsers block rendering of elements below an external script until the script arrives and is parsed and executed. Since many sites put scripts in the HEAD, this means the entire page is typically blank. That’s why I believe the most important web performance coding pattern for today’s web sites is to load JavaScript asynchronously. Not only does this improve performance, but it avoids making external scripts a possible SPOF. 
Stylesheet 
Browsers are split on how they handle stylesheets. Firefox and Opera charge ahead and render the page, and then flash the user if elements have to be redrawn because their styling changed. Chrome, Internet Explorer, and Safari delay rendering the page until the stylesheets have arrived. (Generally they only delay rendering elements below the stylesheet, but in some cases IE will delay rendering everything in the page.) If rendering is blocked and the stylesheet takes a long time to download, or times out, the user is left staring at a blank page. There’s not a lot of advice on loading stylesheets without blocking page rendering, primarily because it would introduce the flash of unstyled content.
inlined @font-face 
I’ve blogged before about the performance implications of using @font-face. When the @font-face style is declared in a STYLE block in the HTML document, the SPOF issues are dramatically reduced. Firefox, Internet Explorer, and Opera avoid making these custom font files a SPOF by rendering the affected text and then redrawing it after the font file arrives. Chrome and Safari don’t render the customized text at all until the font file arrives. I’ve drawn these cells in yellow since it could cause the page to be unusable for users using these browsers, but most sites only use custom fonts on a subset of the page.
Stylesheet with @font-face 
Inlining your @font-face style is the key to avoiding having font files be a single point of failure. If you inline your @font-face styles and the font file takes forever to return or times out, the worst case is the affected text is invisible in Chrome and Safari. But at least the rest of the page is visible, and everything is visible in Firefox, IE, and Opera. Moving the @font-face style to a stylesheet not only slows down your site (by requiring two sequential downloads to render text), but it also creates a special case in Internet Explorer 7 & 8 where the entire page is blocked from rendering. IE 6 is only slightly better – the elements below the stylesheet are blocked from rendering (but if your stylesheet is in the HEAD this is the same outcome).
Script then @font-face 
Inlining your @font-face style isn’t enough to avoid the entire page SPOF that occurs in IE. You also have to make sure the inline STYLE block isn’t preceded by a SCRIPT tag. Otherwise, your entire page is blank in IE waiting for the font file to arrive. If that file is slow to return, your users are left staring at a blank page.

SPOF is bad

Five years ago most of the attention on web performance was focused on the backend. Since then we’ve learned that 80% of the time users wait for a web page to load is the responsibility of the frontend. I feel this same bias when it comes to identifying and guarding against single points of failure that can bring down a web site – the focus is on the backend and there’s not enough focus on the frontend. For larger web sites, the days of a single server, single router, single data center, and other backend SPOFs are way behind us. And yet, most major web sites include scripts and stylesheets in the typical way that creates a frontend SPOF. Even more worrisome – many of these scripts are from third parties for social widgets, web analytics, and ads.

Look at the scripts, stylesheets, and font files in your web page from a worst case scenario perspective. Ask yourself:

  • Is your web site’s availability dependent on these resources?
  • Is it possible that if one of these resources timed out, users would be blocked from seeing your site?
  • Are any of these single point of failure resources from a third party?
  • Would you rather embed resources in a way that avoids making them a frontend SPOF?

Make sure you’re aware of your frontend SPOFs, track their availability and latency closely, and embed them in your page in a non-blocking way whenever possible.

Update Oct 12: Pat Meenan created a blackhole server that you can use to detect frontend SPOF in webpages.

9 Responses to Frontend SPOF

  1. about putting scripts at the bottom, i found a way I didnt saw elsewhere for those who dont want to rewrite portion of JS code like Facebook or Google Analytics did :

    - save the onerror then mute the JS errors on the page
    - display page, including inline JS calls
    - put back the default JS error handler
    - include the JS
    - list the of the page, eval them

    more code and graphics here (post in french, sorry)
    http://jpv.typepad.com/blog/2010/05/performances-web-put-scripts-at-the-bottom-oui-mais-comment-.html

  2. last step is
    - list the <script> of the page, eval() them

  3. There is nothing deferred about Google Analytics’ async snippet, it is only loaded in a non-blocking way.

    In fact it is supposed to be put in the [1] whereas we were told to place the old one right before the tag.[2]

    So it is less deferred now, than it was before. The reason it has changed is that now you can place it in the head without worrying about other elements to be delayed as a consequence. Also, you get more accurate statistics because there are less things that may delay or block your tracking (as this article points out).

    Anyway, shutting down error handling is not one of those so-called “best practices”.

    If you want to solve it more elegantly you may want to check out Peter Michaux article about after-DOM-load execution. [3]

    For basic things, Facebook’s way is enough. But what they do is they use a global event handler for all the events on the page, so there is no need to attach them inline or after the onload. Thus, the functionality of elements are handled in one place instead of tons of small event handlers. It scales nicely if you ask me. :) [4]

    There are also some nice techniques about deferred execution on this blog. [5]

    Finally, tweaking is always the worst thing to do, rewriting or refactoring code can be costly in a short term, but with some hours of work now you can save weeks of confusion later. Especially if you are working in a team.

    [1] http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html

    [2] http://code.google.com/apis/analytics/docs/tracking/gaTrackingOverview.html

    [3] http://peter.michaux.ca/articles/the-window-onload-problem-really-solved

    [4] http://www.slideshare.net/makinde/javascript-primer

    [5] http://www.stevesouders.com/blog/2009/12/07/downloading-javascript-as-strings/

  4. stripping tags, bites :) wordpress hasn’t got htmlspecialchars() or somethin’? …

    Anyaways, errata: “In fact it is supposed to be put in the {head}[1] whereas we were told to place the old one right before the tag {/body}.[2]“

  5. when I say “inline JS”, I’m not talking about stuff like Peter Michaux is using <input onfocus=”…”> but rather
    <script>
    MY.enrichForm(‘myid’);
    </script>

    and the problem I tried to solve was having put JS dependancies at the bottom of the page but JS functions still called inline. Ideally, I would have made a big page manager waiting for the body.onload before running the functions, but that’s not the way my site’s framework works

    for the new async ga.js the calling of the methods (say _trackPageview and _setAccount) are defered, until the full file is there. Yes it’s loaded in a non-obstrusive way, but the innovation of GA was that you can call all of the GA methods without the JS dependancy being actually here.

    FB solves the problem of calling a JS action that is defined in a file that is still not arrived by having a generic listener, that will extract info from the markup to know what to do and get via XHR the JS+HTML (if needed) generated on the server-side.

    both solutions were requiring more changes than I wanted to, and the one I finally found is perfectly maintainable

    In my technique, the muting of the JS errors just lasts the time of loading the HTML, to prevent inline JS call to warn the user, then I re-enable the default one. The functionality of the error handling is preserved.

  6. Inline scripts are a bad practice. Again, the idea is to separate the markup(HTML) from the presentation(CSS) and extra functionality(JS).

    Moreover: “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.” [1]

    I also think that browsers don’t appreciate bunch of meaningless code inside the page, for you may not catch errors, but they will still try to parse and execute it over and over again.

    You can put your inline scripts into js files, that are included at the end of the page by some server side logic depending on the request url.

    Or it is not that hard to write code that deals with HTML elements by checking if they are actually there. So you can make the whole thing external and enjoy the advantages of caching.

    Also, during loading of the HTML lot of things can happen. Event listeners can go mad, users can cause problems that you may not be prepared for. Silencing error handler is a very very bad practice.

    No offense, using this technique is one thing, but encouraging others to use it as well is just plain awful.

    The best tweaking is no tweaking.

    [1] http://www.stevesouders.com/blog/2009/05/06/positioning-inline-scripts/

  7. Thanks for the great article.

    However, it’s still unclear to me, if Front End SPOF is better solved by: a) async loading third party scripts, or b) putting all s at the bottom of the .

    What’s the diff when speaking about SPOF?

    Thanks again!

  8. @Michael: Async is better because it’ll render the snippets sooner but won’t block the main content of the page. Also, depending on the browser, it will allow the onload event to fire.

  9. This would be a good spot to discuss base64 encoded fonts placed directly in the css file. In the same way you might use background-image: url(data:image/png;base64,…);