P3PC: Digg Widget

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.