About Insanely Stupid Code

When looking into a JS-problem on an Autoptimized site, it turned out missing semi-colons messed things up. Missing semi-colons make JS un-minifyable, as eloquently explained by master-minifier and JS-guru Douglas Crockford in this Bootstrap issue from back in the day;

That is insanely stupid code. I am not going to dumb down JSMin for this case.

(When) should you Try/Catch Javascript?

Autoptimize comes with a “Add try-catch wrapping?”-option, which wraps every aggregated script in a try-catch-block, to avoid an error in one script to block the others.
I considered enabling this option by default, as it would prevent JS optimization occasionally breaking sites badly. I discussed this with a number of smart people and searched the web, eventually stumbling on this blogpost which offers an alternative for try-catch because;

Some JavaScript engines, such as V8 (Chrome) do not optimize functions that make use of a try/catch block as the optimizing compiler will skip it when encountered. No matter what context you use a try/catch block in, there will always be an inherent performance hit, quite possibly a substantial one. [Testcases] confirm [that] not only is there up to a 90% loss in performance when no error even occurs, but the declination is significantly greater when an error is raised and control enters the catch block.

So given this damning evidence of severe performance degradation, “try/catch wrapping” will not be enabled by default and although Ryan’s alternative approach has its merits, I’m weary of the caveats so I won’t include that (for now anyway). If your site breaks when enabling JS optimization in Autoptimize, you can enable try/catch wrapping as a quick workaround, but finding the offending script and excluding it from being optimized is clearly the better solution.

Javascript tip: visualizing DOM events

At work we were stumped by a simple link that upon clicking didn’t have the browser request the target page. Our supplier investigated using VisualEvent, a bookmarklet-initiated javasript-tool that goes through a page and visualizes all events on DOM nodes. The developer released VisualEvent 2 a couple of days ago (also on GitHub), which I played around with for a bit and it really is great for debugging purposes!

The culprit for the “broken” link by the way was a bug in an old version of SmoothScroll, a jQuery-plugin by fellow Belgian Mathias Bynens which ensures smooth scrolling when clicking on a in-page link. The plugin did check if the link was to an anchor on the same page, but it had already prevented the default action before that check was made, resulting in the broken link. The current version of the plugin does the check before the default action is prevented, so all is well, your weekend can start. Enjoy!

How to do jQuery templates with jQote2

For a proof of concept I was preparing at work I needed a jQuery templating solution. Although there is beta templating support (contributed by Microsoft) in jQuery, I decided to implement jQote2 instead. This alternative jQuery plugin is small (3,2Kb minimized, 1,7Kb compressed), versatile and most importantly very, very fast!
So what do you need to know about jQote2 to get it working? Well, there’s 3 ingredients; data, template and javascript-code to put the data in the template.
The data can be fetched from an external source, e.g. this call to the iRail-api for departures from Brussels North.
The template is basically just HTML with some placeholders for your data:

<script type="text/x-jqote-template" id="liveboard_tmpl">
 <tr>
  <td class="left">
   <%= this.station %>
  </td>
  <td class="right">
   <%= this.time %>
  </td>
  <td class="right">
   <%= this.platform %>
  </td>
 </tr>
</script>

The javascript fetches the data using jQuery’s getJson, parses all departures in the template and adds the resulting HTML to an element in your DOM (in this case #liveboard’):

<script type="text/javascript">
$(document).ready(
	function() {
		$.getJSON(
			'http://api.irail.be/liveboard/?format=json&station=Brussel%20Noord&lang=EN&arrdep=DEP&callback=?',
			function(data) {
					$('#liveboard').jqoteapp('#liveboard_tmpl', data.departures.departure);
			}
		)
	}
);
</script>

Off course the UNIX-timestamp in this.time isn’t really usable, but we can easily add some javascript to the template, just before outputting the time, to fix that;

<% this.time=((new Date((Number(this.time))*1000)).toLocaleTimeString()).substr(0,5); %>

That’s right, use “<%” instead of “<%=” and you can mingle javascript in the template. To only show trains that have not left and to show departures including delay, the template looks like this:

<script type="text/x-jqote-template" id="liveboard_tmpl">
<% if (this.left!="1") { %>
 <tr>
  <td class="left">
   <%= this.station %>
  </td>
  <td class="right">
   <% if (this.delay!="0") {
    this.time="<span class=\"delayed\">"+((new Date((Number(this.time)+Number(this.delay))*1000)).toLocaleTimeString()).substr(0,5)+"</span>";
   } else {
    this.time=((new Date((Number(this.time))*1000)).toLocaleTimeString()).substr(0,5);
   } %>
   <%= this.time %>
  </td>
  <td class="right">
   <%= this.platform %>
  </td>
 </tr>
<% }; %>
</script>

Add some CSS and you’ll quickly have something like the demo you can find here. Just look at the code, it’s pretty straightforward and check out the jQote2 reference for even more info.

Firefox 4 beta007: the thunderball we’ve been waiting for

Although the final release of Firefox 4 has been postponed until the beginning of next year, the latest beta-iteration of our little browser-friend is a huge step forwards!
Up until beta6 a number of very nice features had already been added; tabs on top and grouped tabs, a new add-on manager, Firefox sync, lots of HTML5- and CSS3-features, support for the webm video codec, support for WebGL (3D on the canvas), hardware accelerated graphics, …
But despite all of these exiting changes, there was one elephant in the room; javascript speed. Chrome and Safari were miles ahead and even Opera and Microsoft IE9 were boosting important advances in that area. And that is where beta7 makes a huge step forward; Firefox 4 sports a new Javascript-engine and is now in the same league as Chrome and Safari even beating them in some tests and that speed difference is immediately obvious after upgrading from beta6 tot beta7.
So Firefox 4 is getting ready for prime-time; lots of great new features, fast and -in my experience- very stable. Guess it’s time to upgrade my lovely wife’s Firefox 3.6.x to the brand new 4 beta 7! I do hope she’ll find the location of the reload button though …

High performance YouTube embeds

It’s all about speed! I mean, you want your visitors to stick around, enjoying your content instead of waiting for stuff to download, no? And I bet you would love Google to consider your site quick, now that speed has been confirmed to have an impact on search ranking?
“High Performance web sites”-guru Steve Souders is doing incredible work studying the impact of 3rd party content -and especially javascript-based services such as analytics and bannering- on the performance of a web site.
An entirely different type of 3rd party content is Flash video, especially YouTube embeds, but there are a number of indicators that these indeed do impact performance as well:

  • opening a page with embedded YouTube can take some time when on dialup (or mobile data)
  • YouTube-heavy pages tend to slow down older computers (flashblock or adblock anyone?)
  • Facebook doesn’t really embed YouTube by default, but uses a placeholder with a thumbnail instead that is replaced by the embedded YouTube only when clicked
  • Google Webmaster Tools “Site Performance” seems to sometimes single out pages with YouTube embeds (e.g. stating that there is a DNS-resolution overhead)

Indeed, when testing this simple page with some text and 2 embedded YouTube clips on webpagetest.org, these were the main results (full results including nice graphs here):

  • (base) download complete: 0.356s for 2KB
  • start render: 0.426s
  • full page download complete: 3.005s for 315KB

There’s good and bad news in those figures. As could be expected the YouTube Flash embed doesn’t impact the rendering of the base page. But 2.6 seconds and 312KB just to display 2 video’s a visitor might not even bother to look at (I bet that the click-rate for embedded YouTube video is somewhere between 2 and 20%), that’s … sub-optimal?
So I threw some JavaScript at my computer to build an alternative to the default YouTube embed, the main goal being to build a Flash-less initial view with only a few lines of html/javascript which at some point people could copy/paste in their site just like they do now. And LYTE (Lite YouTube Embed) came into the world.
The main results when testing this LYTE-test-page on webpagetest.org (full results here):

  • (base) download complete: 0.324s for 4KB (which is marginally faster)
  • start render: 0.363s (again marginally faster)
  • full page download complete: 0.803s for 35KB (leaner, meaner and faster!)

The code that would have to be copy/pasted (multi-line for clarity):
<div class="lyte" id="gnDh6PqWqD8" style="width:480;height:385;"><noscript><a href="http://youtu.be/gnDh6PqWqD8">Watch on YouTube</a></noscript>
<script>(function(){d=document;if(!document.getElementById('lytescr')){lyte=d.createElement('script');lyte.async=true;lyte.id="lytescr";lyte.src="http://futtta.be/lyte/lyte.js";d.getElementsByTagName('head')[0].appendChild(lyte)}})();</script></div>

The nitty-gritty (do skip if you’re not inclined to get aroused by technical details): this code attaches (a minified version of) lyte.js to the page’s head. The real work is done in that javascript-file: get all divs with class-name “lyte” (with a hack for friggin’ IE inlined), use the videoid which is in the divs’ id to fetch the thumbnail and title from YouTube, display these in a fashion which is very YouTube-like and add an onclick eventhandler to replace the fake with a real player when clicked (and remove the eventhandler to clean things up).
So using LYTE you can embed YouTube in such a way that the amount of data, the total download time and the total rendering time are significantly lower, without loosing any functionality.
And this -to conclude this long post- is what LYTE looks like (soundtrack by Nôze – “Meet me in the toilet”, it’s Friday after all);

No more jsonp for Google geocoding webservice?

I needed to do some reverse geocoding in a javascript webapp. The Google Maps API worked flawlessly, but it seemed overkill to load all that javascript just to do one lousy reverse geocoding lookup (esp. on a mobile device, my target platform).  I searched some more and found the Google geocoding webservice, which is invoked with a simple HTTP GET request and returns the response in JSON. Version 2 of this service works great, as you can specify a callback-function to do jsonp (a simple method to allow for cross domain ajax requests),
This example request for v2, http://maps.google.com/maps/geo?q=51,4&sensor=false&output=json&callback=parseme, results in a response containing a call to your own “parseme”-function, with the json-object as the payload;

parseme && parseme( {
"name": "51,4",
"Status": {
"code": 200,
"request": "geocode"
},
"Placemark": [ {
"id": "p1",
"address": "Brukkelen 191, 9200 Dendermonde, Belgium",
...
]})

But a month ago Google announced a new version of their geocoding webservice and the documentation for V2 mentioned that it was deprecated in favor of the Geocoding V3 Web Service. so I switched to the new API, only to discover that callbacks aren’t supported any more.
An example request for v3 http://maps.google.com/maps/api/geocode/json?latlng=51,4&sensor=false&callback=parseme results in nothing but the javascript-object:

{
"status": "OK",
"results": [ {
"types": [ "street_address" ],
"formatted_address": "Brukkelen 191, 9200 Dendermonde, Belgium",
...
]})

And that, my dear fellow travellers, sucks big time. JSON without the P means we’re back to useless proxy-scripts on our servers. So until Google lets Jason pee (sorry folks, I just had to write this) in the V3 geocoding webservice, I’ll continue using the deprecated V2 with sweet -but undocumented- callback!

Avoid iframe-scrollbars with squeezeFrame.js

I know, this seems to have become an obsession of mine, but here I am again with a follow-up on my iframes-tips blogpost. You might remember I advised against disabling scrollbars on iframes, because;

Disabling them will render the iframe partially inaccessible for some of your users, because the size your iframe-content needs, depends on things outside your control such as operating system & versions (e.g. font & screen resolution), browser (e.g. css-implementation) and browser configuration (e.g. non-default font-size).

But what if you could resize (generally: zoom out) the iframe-content to perfectly fit the available width and height, thus avoiding vertical and especially horizontal scrollbars? Well, that is exactly what squeezeFrame.js tries to do (using css zoom and -moz-transform:scale in Firefox)! Just include the javascript-file in the iframe-content page and set a few options if you want to change the default behavior (which is: zoom in/out for width only, max. + or – 5%).
squeezeFrame.js was tested successfully in Firefox 3.6, IE6, Safari4 and Chrome4, but does not work in Opera 10.5. More info (including some “known issues”) can be found on the demo-page and in the javascript-code off course.
As always; reply in the comments or contact me if you find bugs or have problems.

Fix iframe-positioning problem with frameMagic.js

A short followup on my previous post about iframes; as I happen to like simple drop-in solutions, I updated the javascript that handles the ‘blank 2nd page in an iframe bug’ to automagically work upon inclusion in the html.
So if you happen to have problems with the positioning of 2nd (or later) pages in iframes (due to the top part of the iframe not being visible in the ‘viewport’), just upload frameMagic.js to your webserver and add the following to the head of your html to ease your iframe-blues;

<script type="text/javascript" src="path/to/frameMagic.js"></script>

Optionally you can specify which iframes are to be treated this way (excluding the other ones) by doing

<script type="text/javascript">
var fM_conf="iFrame1,iFrame3";
</script>

You can find more information and examples on http://futtta.be/frameMagic.