The Cost Of "Social Media" Javascript Overload

Your Site Doesn't Need 50+ <script> Blocks. Really.

With the continued growth of cloud[y*], "opening up" of anything and "[noun] as a [noun]" web services these days, it's become quite common to load one's site up with little bits of Javascript from all over the web; eg. <script src="http://example.com/cool/js/api/">

The amount of script referenced and required has increased simply with libraries such as YUI and jQuery alone, but third-party stats/analytics packages, Google AdSense, "social media" services, "blog this", "bookmark/Digg this" buttons et al all encourage copying and pasting countless snippets of code which you can use to add their widget magic to your site.

Third-party script introduces dependencies, impacts performance and affects security.

"Opening Up" Risk: Script Security Holes (Or, Trust)

Having a handful of third-party-hosted widgets on your site might make it seem more hip, but hipness comes at a cost; it will also guarantee your site will take longer to load. Additionally, you open your site to potential hanging and "downtime" if any of the third-party sites go down and also become open to XSS security vulnerabilities by the same measure, should any one of them become compromised.

While the Javascript/DOM model could be considered flawed in that there is currently no cross-domain security or restrictions on what remotely-loaded script can do (it has the same permissions your local script does), it is arguably no wiser to blindly assume and trust that third-party code used on your site will not be compromised at any point. Despite security concerns, "remote <script>" is dead simple and works most of the time - so it's a de-facto standard.

<script> Performance Penalties

By default, script blocks do what their name implies - that is, they block the rendering of the document - until they have loaded or timed out. In the best case, caching kicks in for both the DNS lookup for the third-party domain and the HTTP request for the script itself, so things load immediately. In the worst case, the remote host is down and not responding, and the script node freezes the rendering of the page until the browser finally gives up and closes the HTTP request. To help fight this, you can defer loading of third-party Javascript, and/or asynchronously load script using Javascript itself. Either approach has the benefit of not blocking the browser.

Following the script node blocking behaviour, inline <script> nodes can also interrupt the browser's layout/flow process, and thus it is worth considering deferring your inline script blocks or reducing the number of script blocks by combining them, ideally forming a single block. There may be a trade-off here of UI responsiveness and load time, which has yet to be investigated in detail; Steve Souders has some articles on loading scripts without blocking, which provide specific examples. Browsers vary on the maximum number of simultaneous HTTP connections they can make as well as the limit of per-domain HTTP connections, so you may be best to lean towards a lowest common denominator.

"Social Media Javascript Overload" In The Wild

A quick survey of a few popular technology blogs (and a newspaper) reveals a rather disturbing amount of third-party script nodes, as well as significant numbers of inline script blocks. Some are for social/sharing things, but there is a lot of advertising script being loaded as well.

One might wonder if blocking third-party scripts would render these web sites unusable. Given the "plug-in" nature of most of these scripts, little is seen as breaking; extensions like NoScript and AdBlock Plus have come in to help prevent potential XSS vectors and block ads, with the side effects of reduced bandwidth and faster load time (and to the publisher, presumably, denied ad revenue and stats tracking etc.)

Site <script> nodes Off-domain Inline Code size Load time / Grade
techcrunch.com 110 40 70 ~295KB ~9sec/F
12 unique domains (b.scorecardresearch.com, edge.quantserve.com, spa.snap.com, google-analytics.com, services.crunchboard.com, cache0.techcrunch.com, ad.doubleclick.net, tweetmeme.com, d.techcrunch.com, shots.snap.com, i.ixnp.com, js.meebo.com)
readwriteweb.com 115 67 43 ~129KB ~16sec/E
21 unique domains (log.enquisite.com, s7.addthis.com, statcounter.com, ad.doubleclick.net, static.fmpub.net, static.crowdscience.com, d.openx.org, textads.fmpub.net, static.xgraph.net, edge.quantserve.com, burstnet.com, twitter.com, d1.openx.org, adserver.adtechus.com, burstnet.com, cetrk.com, m1.2mdn.net, google-analytics.com, ping.crowdscience.com, ajax.googleapis.com, google.com)
mashable.com 87 49 36 ~156KB ~21sec/E
21 unique domains (ar.voicefive.com, google-analytics.com, b.scorecardresearch.com, edge.quantserve.com, static.fmpub.net, ds.serving-sys.com, bs.serving-sys.com, pubads.g.doubleclick.net, cdn.eyewonder.com, digg.com, m1.2mdn.net, ad.doubleclick.net, mashable.jobamatic.com, stats.wordpress.com, google.com, static.addtoany.com, mashable.tags.crwdcntrl.net, partner.googleadservices.com, static1.blippr.com, ec.mashable.com, ajax.googleapis.com)
nytimes.com 60 40 20 ~219KB ~9sec/E
5 unique domains (graphics8.nytimes.com, amch.questionmarket.com, ad.doubleclick.net, markets.on.nytimes.com)

The technology sites are very script-heavy and take noticeably longer to load than most sites. ReadWriteWeb and Mashable seem to be the slowest, though RWW look to be doing a good job of having very little script loading from directly from their web servers (ie., using a CDN.) That both load script from 21 unique remote domains seems to be rather ridiculous, but perhaps this is the reality of ads + tracking + social stuff + libraries. If possible, a roll-up would help.

Content accessed Sunday, August 30th 2009. YSlow grades thrown in for fun. Post-load script count:

(function(){
  var s = document.getElementsByTagName('script');
  var src = 0;
  var srcURLs = [];
  for (var i=s.length; i--;) {
    if (s[i].getAttribute('src')) {
      src++;
      srcURLs.push(s[i].getAttribute('src'));
    }
  }
  console.log('total: '+s.length+', external: '+src+', inline: '+(s.length-src));
  console.log('URLs: '+srcURLs.join('\n'));
})();

Bandwidth calculated via YSlow 2.0 stats. Load time approximated from Safari 4, resources/time panel on OS X Snow Leopard, Comcast cable in SF. External number above includes script URLs on same domain, manually excluded for table. Given the dynamic nature of web sites and rotating ads, stats will vary slightly per page. YSlow may not include dynamically-loaded scripts in bandwidth stats.

OK, So Now What?

Perhaps you're a developer on a site that includes a lot of third-party widgets, etc. Look into loading non-crucial, "deferrable" script later in the page if possible, using Javascript itself. Consider rolling up script references and using a CDN where appropriate, and concatenating, eliminating or otherwise reducing the number of inline script blocks.

In a sentence: Avoid doing work early, and avoid it entirely if at all possible. ;)

Related links