P3PC: Digg Widget

February 28, 2010 1:33 pm | 10 Comments

Update: In March, 2010 Digg revamped their snippet to have much better performance. See their blog post Speeding Along

P3PC is a project to review the performance of 3rd party content such as ads, widgets, and analytics. This blog post looks at the Digg Widget. Here are the summary stats:

impact on page Page Speed YSlow doc.
write
total reqs total xfer size JS ungzip DOM elems median Δ load time
big 90 84 y 9 52 kB 107 kB 84 667 ms
column definitions
Click here to see how your browser performs compared to the median load time shown above.

The Add a Digg Widget page describes how to insert this widget into a page. Here’s what it looks like:

Snippet Code

Let’s look at the actual snippet code:

1: <script type=”text/javascript”>
2: digg_id = ‘digg-widget-container’; //make this id unique for each widget you put on a single page.
3: digg_title = ‘Top 10 list from Technology’;
4: </script>
5: <script type=”text/javascript” src=”http://digg.com/tools/widgetjs”></script>
6: <script type=”text/javascript” src=”http://digg.com/tools/services?type=javascript&amp;callback=diggwb&amp;endPoint=%2Fstories%2Fcontainer%2Ftechnology%2Ftop&amp;count=10″></script>
snippet code as of Feb 23, 2010

A quick walk through the snippet code:

  • lines 1-4 – Variables used later in the loaded scripts.
  • line 5 – The “widgetjs” script is where most of the action takes place.
    This script uses document.write to load a stylesheet and two more scripts:

    1: document.write(‘<link rel=”stylesheet” type=”text/css” media=”all” href=”http://digg.com/css/widget.css” />’);
    2: document.write(‘<script type=”text/javascript” src=”http://cotnet.diggstatic.com/js/loader/380/JS_Libraries,jquery|JS_Libraries,jquery-noconflict|jquery-dom”></script>’);
    3: document.write(‘<script type=”text/javascript” src=”http://digg.com/tools/widgetjsvars”></script>’);

    The “widgetjsvars” script does several document.writes including loading another script:

    1: document.write(‘[…]<script src=”http://cotnet.diggstatic.com/js/loader/395/omnidiggthis” type=”text/javascript”></script>’);
  • line 6 – The “/tools/services” script contains the data (stories) for the widget.

Performance Analysis

This HTTP waterfall chart was generated by WebPagetest.org using IE 7 with a 1.5Mbps connection from Dulles, VA. Item 10 (digg-waterfall.png) is the first resource that’s part of the main page. Notice how it’s blocked by the Digg widget’s scripts.

Here are the most important performance issues along with recommended solutions.

  1. 9 HTTP requests, 52 kB transferred over the wire, and 107 kB of JavaScript (uncompressed) is a lot of content for a single widget.
    Recommendations:

    • Concatenate these three scripts: JS_Libraries, widgetjsvars, and omnidiggthis. (eliminates 2 HTTP requests)
    • Run Page Speed’s “Defer loading JavaScript” feature and see how much of the JavaScript is not used. If it’s sizable, delete it. (This feature is currently broken in the latest version of Page Speed, but a fix is imminent.) (eliminates ?? kB)
    • Optimize the images – widget-logo.png and get-widget.png can both be reduced by ~3 kB. (eliminates ~6 kB)
    • Sprite widget-logo.png and shade-com.png. (eliminates 1 HTTP request)
  2. The widget’s scripts block the main page’s content from downloading. Looking at the waterfall chart, the main page includes the image “digg-waterfall.png” (row 10). Notice how this image doesn’t start downloading until after all the scripts for the Digg widget are received.
    Recommendations:

    • Instead of loading the scripts using document.write, load them without blocking other downloads. The scripts are already suffering from race condition behavior, as evidenced by this comment from widgetjsvars:
      1: if (!digg || !digg.$) setTimeout(function() { diggwb(obj); }, 200); //hack for IE not loading scripts that are included via document.write until it decides too

    So it probably isn’t too much work to avoid race conditions when making all the scripts load asynchronously.

  3. The widget’s stylesheet blocks the main page from rendering in IE.
    Recommendations:

    • Instead of loading the stylesheet using document.write, load it via JavaScript as described in 5d dynamic stylesheets.
  4. Four of the resources aren’t cached long enough.
    Recommendations:

    • Two scripts aren’t cacheable because they have an expiration date in the past. widgetjs is part of the snippet, so it can’t have a long expiration date, but something like an hour or a day would be better than a date in the past. widgetjsvars could have a far future expiration date since its URL is specified in widgetjs.
    • The three images are only cacheable for a day. They should have a far future expires header since the image filename can be change if it’s modified.
  5. There are approximately 30 inefficient CSS selectors. Because this stylesheet is part of the main page, the selectors will cause the overall page to render more slowly when these selectors are applied to the elements in the main page.
    Recommendations:

  6. Four of the resources have ETags which reduces their cacheability.
    Recommendations:

    • Configure the ETags for widget.css, widget-logo.png, get-widget.png, and shade-com.png.

What you can do now: Because the Digg Widget uses document.write, the best thing you can do to reduce the impact it has on your page is to put it in an iframe. This will remove the blocking effect it has on your page.


10 Responses to P3PC: Digg Widget

  1. Curiously, first script creates 2 “variables” via undeclared assignment. This is a bad practice (for example, it will throw errors in strict mode of ES5).

    The script following it includes an entire jQuery (as you have already mentioned), which is about 23KB gzipped. This isn’t a terribly lot, but considering that they only use few more-or-less trivial jQuery methods, one of the biggest savings would be to replace jQuery with a set of custom JS helpers. This would bring JS down from 23 to about 3-5 KB. And that’s a saving of ~20 KB.

    The script after jQuery continues with undeclared assignments, polluting global scope with 14 more “variables” (albeit, prepended with “digg_”). It’s not clear why they couldn’t encapsulate it all for internal use of a widget.

  2. @kangax: You’re right about jQuery, but recall that Digg is the site that once loaded jQuery, Prototype, and a third library (can’t recall which) on every page.

  3. Hi Steve.

    As you say for few times, 3rd party content are really painful for speeding up website.

    Hopefully, even if they (3rd party content providers) do not want to make efforts, we can use tips for a faster impression of rendering. What’s your opinion on this kind of tip ? Do you have a better solution ?
    http://www.speedingupwebsite.com/2010/02/17/removing-blocking-adsense/

  4. Very interesting analysis.

    I would love to see something like this done for Omniture Sitecatalyst, so that I have you in my corner, next time I have a conversation with them about performance :-)

  5. I do believe you’d have some fun with IntenseDebate or Disqus, Steve. :)

  6. The “Compare” link seems broken.

  7. @Leandro: I had a webhosting issue this morning. Should be fixed now.

  8. @Bruno: These techniques are definitely possible, but tricky to get right across all browsers. I don’t see a working example in that blog post, for example.

  9. I’ve documented how to make scripts that use document.write non-blocking here:
    http://tech.bluesmoon.info/2010/01/handling-documentwrite-in-dynamic.html

  10. Kudos to Digg for responding to this review and following all the best practices now: http://about.digg.com/blog/speeding-along