Sunday, October 18, 2009

geocitieslycostripod.com

Just deployed a new site to display my HTML5 learnings so far.

The idea is to demonstrate the proper use of the section, article, time, header and footer tags. I might have used a couple others. I've also used some CSS3 text-shadow rules for the first time ever in a production website. I hope to get positive comments from you about the site.

So go to my new site: http://geocitieslycostripod.com for the full glory of HTML5.

PS. Hey, I didn't say anything about Web 1.0 or Web 2.0 or anything!

Saturday, August 22, 2009

Songs In Code

Christian Heilmann of YDN fame, started a meme on twitter for writing songs in code, within the 140 char limit of course. Participation was simple: simply add a hashtag of #songsincode to the tweet. Quite soon, it became a trending topic on twitter. One way to look at it is that people on twitter have nothing to do, but the more likely one is that geeks found something to kill time with on a Friday.

Of course, quite a few gems came out of it. I'm listing a couple of my favourites below:

  • !my.isLover(billyJean) && billyJean.claims(my.theOne) && !my.isSon(theKid)
  • while (countdown > FINAL)
      countdown--;
  • public void setShirt(Shirt s){
        throw new ImTooSexyException(s);
    }
  • if (this.streets.name == undefined) {
        _root.where = this
    }
  • SELECT person WHERE AGE > 12 AND AGE <20 AND SMELLS LIKE '%SPIRIT%
  • <span style="color:#f00">
        <span style="color:#f00">wine</span>
    </span>
  • if(me.crazy.go()){
        you.call(meSuperman)
    };
    function meSuperman(){
        return '?' //Kryptonite
    }
  • .clowns{float:left;}
    .jokers{float:right};
    #me_you{position:fixed;margin:0 auto;width:100%}
  • var i = {shot:{sheriff:true,deputy:false}}
  • try{if(money>0 && work=='' && chicks=='free'){
        throw 'that ain\'t working'
    }}
  • class HotelCalifornia {
        void checkOut () {
            canLeave=false;
        }
    }
  • while(1){
        try {
            Britney.Sing();
        } catch (Exception ex) {
            throw new Exception("Oops");
        }
    }
  • UPDATE people SET parent_occupation = 'preacher man' WHERE has_pleased = 1
  • ["step", "move"].forEach(i.watchingYou);
  • (defun get (x) (if (neq x 'satisfaction) (error)))
        (get (not satisfaction)) ;
  • 99.times {Ballon.new(:red)}

Friday, March 20, 2009

Downloading JavaScript Files in Parallel

Update: There were some bugs in the code here, which have been fixed. If you were using the older version of this script on your site, you should update it.
Also, a lot of people have got back to me about them getting undefined symbols, so I've highlighted parts of this post that are absolutely critical for it's functioning.

Steve Souders, creator of YSlow, author of the book High Performance Web Sites, is back in action writing a book titled Even Faster Websites. In it he details what one can do after the 14 YSlow rules (laws?) have been implemented, and you still want better better performance.

6 days ago, Steve gave a talk at SXSW Interactive, the slides of which are available on Slideshare. In it, he goes on to suggest (slide 27), that we should load scripts without blocking. To me, this seems like a very interesting idea, and based on his hints in the next few slides, I started experimenting.

Let me back up a little. When browsers download scripts, they block all other resources from downloading until such time that the script has finished downloading. When I mean all other resources, it includes even other CSS files and images. There are several ways to reduce the impact of serial script download, and the High Performance Websites book makes a couple of good suggestions.

  • Rule 1 - Make Fewer HTTP Requests
  • Rule 5 - Put Stylesheets at the Top
  • Rule 6 - Put Scripts at the Bottom
  • Rule 8 - Make JavaScript and CSS External
  • Rule 10 - Minify JavaScript

There are several others, mostly around caching strategies and reducing HTTP overhead, but these alone reduce the impact of serial script download significantly.

Now, if you haven't already taken care of these rules of optimization, my suggestion will be hard to implement, or will reap no benefits. You can stop reading now, and go back to your site to optimize your code.

Regular <script> tags:

Serial script download

See that waterfall pattern of file downloads? Nothing else is downloaded when a script is being downloaded, not even other scripts. The time gap between successive downloads is the time taken to evaluate the script, roughly proportional to the size of the script. Notice also that this takes in excess of 600ms even when the files are being served from my local machine, effectively having near-zero network latency.

With script parallelization

Parallel script download

Now, this looks much better, doesn't it? Not only has everything downloaded in parallel, it has taken less than half the time for the same size of files. In fact, you will notice that some noise when recording this data made the files take longer to download in this case, yet the total time was less than half of the pervious case.

So, how did I do this? Read on...

One script tag to rule them all

Reading into Souders' suggested techniques (If you still have that slideshow open, go to slide 26), I decided that what I wanted was:

  • I want the browser busy indicators to show,
  • I want a script that doesn't care if I'm downloading from the same domain or not, and
  • I wanted to preserve the evaluation order in case of interdependent scripts.

So, I came up with the following little script:

<script type="text/javascript">
(function() {
var s = [
"/javascripts/script1.js",
"/javascripts/script2.js",
"/javascripts/script3.js",
"/javascripts/script4.js",
"/javascripts/script5.js"
];

var sc = "script", tp = "text/javascript", sa = "setAttribute", doc = document, ua = window.navigator.userAgent;
for(var i=0, l=s.length; i<l; ++i) {
if(ua.indexOf("Firefox")!==-1 || ua.indexOf("Opera")!==-1) {
var t=doc.createElement(sc);
t[sa]("src", s[i]);
t[sa]("type", tp);
doc.getElementsByTagName("head")[0].appendChild(t);
} else {
doc.writeln("<" + sc + " type=\"" + tp + "\" src=\"" + s[i] + "\"></" + sc + ">");
}
}
})();
</script>

It's a little ugly: There's a user-agent sniff happening in there and I've written it so as to use the least number of bytes possible (save for the indentation), but it works, and has no dependencies on any library. Just modify the array on top to place your list of scripts you wish to include, and let the rest of the script do the dirty work. If you need to include scripts from another domain, just use an absolute path.

This code was written keeping in mind that this should be the only piece of on-page inline JavaScript. This can then go on and fetch the script required in parallel, and those in turn can unobtrusively do their thing.

This works as advertised in IE and FF. I haven't tested the parallelization in other browsers, but at least it fails gracefully and preserves script execution order. This has now been tested in Safari, Chrome and Opera as well, and works as advertised everywhere.


Find this interesting? Follow me on twitter at @rakesh314 for more.

Wednesday, January 21, 2009

JsMemcached.js - A Jaxer client for memcached

Two days ago, on a lazy evening, I started work on my first solid Jaxer project — building a memcached client. As a testimony to the elegance of JavaScript, it took me less than 2 hours to get a basic memcached client up and running.

What is memcached, you ask? From the memcached website:

memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

What it does is, lets you use excess RAM on your server machines as temporary stores of data, so that you can avoid going to your DB when you want frequently accessed data. Needless to say, accessing data from RAM is much faster. Since the creation of memcached for LiveJournal.com, memcached has become the cheapest and fastest way to scale a website.

Now, my implementation is not feature complete, nor at peak performance, but I aim to take it there. Even so, I decided to get my code out and available for everyone to see, so that people can tell me what they think of it.

You can go to the Google code page for the JsMemcached-client project, or download the code right away. Though limited in features and with a possible bug in an edge case in the get call, you can start using this already.

This is my first open-source project, so please don't be too harsh in your feedback.

Help needed: I need to figure out how to performance-optimize this code. Either I need to get rid of that loop in the get call, or I need to write a wrapper around libmemcached. I would prefer the latter, since I have to add more features for feature-completeness. Any idea on how I can get Jaxer to talk with libmemcached (or any other such out-of-process thing)?

ShareThis