tag:blogger.com,1999:blog-81121542009-07-13T15:22:02.390+05:30Pieces Of RakeshScraps of Rakesh Pai's lifeRakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.comBlogger213125tag:blogger.com,1999:blog-8112154.post-82886331863972709932009-03-20T16:12:00.006+05:302009-04-28T21:47:28.551+05:30Downloading JavaScript Files in Parallel<p><a href="http://www.stevesouders.com/">Steve Souders</a>, creator of <a href="http://developer.yahoo.com/yslow/">YSlow</a>, author of the book <q><a href="http://www.amazon.com/dp/0596529309?tag=stevsoud-20&camp=14573&creative=327641&linkCode=as1&creativeASIN=0596529309&adid=1S1KP4EV129EN37422C0&">High Performance Web Sites</a></q>, is back in action writing a book titled <q><a href="http://www.amazon.com/Even-Faster-Websites-Essential-Knowledge/dp/0596522304/">Even Faster Websites</a></q>. In it he details what one can do after the <a href="http://stevesouders.com/examples/rules.php">14 YSlow rules</a> (laws?) have been implemented, and you still want better better performance.</p><p>6 days ago, Steve gave a talk at <a href="http://sxsw.com/interactive/">SXSW Interactive</a>, the <a href="http://www.slideshare.net/souders/sxsw-even-faster-web-sites">slides of which are available on Slideshare</a>. In it, he goes on to suggest (slide 27), that we should <q>load scripts without blocking</q>. To me, this seems like a very interesting idea, and based on his hints in the next few slides, I started experimenting.</p><p>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 <strong>reduce the impact of serial script download</strong>, and the <q>High Performance Websites</q> book makes a couple of good suggestions.</p><ul><li>Rule 1 - Make Fewer HTTP Requests</li><li>Rule 5 - Put Stylesheets at the Top</li><li>Rule 6 - Put Scripts at the Bottom</li><li>Rule 8 - Make JavaScript and CSS External</li><li>Rule 10 - Minify JavaScript</li></ul><p>There are several others, mostly around caching strategies and reducing HTTP overhead, but these alone reduce the impact of serial script download significantly.</p><p>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.</p><h2>Regular <code>&lt;script&gt;</code> tags:</h2><p style="text-align: center"><a href="http://www.flickr.com/photos/rakesh/3370655064/" title="Serial script download by Rakesh Pai, on Flickr"><img src="http://farm4.static.flickr.com/3617/3370655064_16f81f38cf_o.png" width="750" height="160" alt="Serial script download" /></a></p><p>See that <q>waterfall pattern</q> 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.</p><h2>With script parallelization</h2><p style="text-align: center"><a href="http://www.flickr.com/photos/rakesh/3369833031/" title="Parallel script download by Rakesh Pai, on Flickr"><img src="http://farm4.static.flickr.com/3552/3369833031_630615b831_o.png" width="753" height="155" alt="Parallel script download" /></a></p><p>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 <em>longer</em> to download in this case, yet the total time was <em>less than half</em> of the pervious case.</p><p>So, how did I do this? Read on...</p><h2>One script tag to rule them all</h2><p>Reading into Souders' suggested techniques (If you still have <a href="http://www.slideshare.net/souders/sxsw-even-faster-web-sites">that slideshow</a> open, go to slide 26), I decided that what I wanted was:</p><ul><li>I want the browser busy indicators to show,</li><li>I want a script that doesn't care if I'm downloading from the same domain or not, and</li><li>I wanted to preserve the evaluation order in case of interdependent scripts.</li></ul><p>So, I came up with the following little script:</p><p><code><pre>&lt;script type="text/javascript"&gt;<br /> (function() {<br /> var s = [<br /> "/javascripts/script1.js",<br /> "/javascripts/script2.js",<br /> "/javascripts/script3.js",<br /> "/javascripts/script4.js",<br /> "/javascripts/script5.js"<br /> ];<br /><br /> for(var i=0, l=s.length; i&lt;l; ++i) {<br /> var sc = "script", tp = "text/javascript";<br /> if(window.navigator.userAgent.indexOf("MSIE")!==-1 || window.navigator.userAgent.indexOf("WebKit")!==-1) {<br /> document.writeln("&lt;" + sc + " type=\"" + tp + "\" src=\"" + s[i] + "\" defer&gt;&lt;/" + sc + "&gt;");<br /> } else {<br /> var t=document.createElement(sc), sa = "setAttribute";<br /> t[sa]("src", s[i]);<br /> t[sa]("type", tp);<br /> document.getElementsByTagName("head")[0].appendChild(t);<br /> }<br /> }<br /> })();<br />&lt;/script&gt;</pre></code></p><p>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.</p><p>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.</p><p>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.</p><hr /><em>Find this interesting? Follow me on twitter at <a href="http://twitter.com/rakesh314">@rakesh314</a> for more.</em><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-8288633186397270993?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com3tag:blogger.com,1999:blog-8112154.post-38666345758378776892009-01-21T19:20:00.003+05:302009-01-22T01:33:18.267+05:30JsMemcached.js - A Jaxer client for memcached<p>Two days ago, on a lazy evening, I started work on my first solid <a href="http://www.aptana.com/jaxer/">Jaxer</a> project &mdash; 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.</p><p>What is memcached, you ask? From the <a href="http://www.danga.com/memcached/">memcached website</a>:</p><blockquote>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.</blockquote><p>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 <a href="http://www.livejournal.com/">LiveJournal.com</a>, memcached has become the cheapest and fastest way to scale a website.</p><p>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.</p><p>You can go to the <a href="http://code.google.com/p/jsmemcached-client/">Google code page for the JsMemcached-client project</a>, or <a href="http://jsmemcached-client.googlecode.com/files/jsMemcached.js">download the code</a> 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.</p><p>This is my first open-source project, so please don't be too harsh in your feedback.</p><p style="border: 1px solid red; background: pink; padding: 5px;"><strong>Help needed:</strong> I need to figure out how to performance-optimize this code. Either I need to get rid of that loop in the <code>get</code> call, or I need to write a wrapper around <a href="http://tangent.org/552/libmemcached.html"><code>libmemcached</code></a>. 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 <code>libmemcached</code> (or any other such out-of-process thing)?</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-3866634575837877689?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com7tag:blogger.com,1999:blog-8112154.post-65172909046377433232008-12-29T19:51:00.004+05:302008-12-29T21:58:43.782+05:30Function declaration vs. function assignment in JavaScript<p>I'm surprised how much I learn about JavaScript every single day.</p><p>It all started with a <a href="http://nedbatchelder.com/blog/200812/internet_explorer_mystery_1376.html">post that's wrongly titled to indicate a bug in Internet Explorer</a>. The comments are an interesting read, where people go ahead to suggest that this "bug" exists in all browsers except Firefox. Then, they discover that it's actually a bug in Firefox, and not the other way round. Then <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=468096">a bug report is filed with Firefox</a>. Brendan Eich comes along and resolves it as an invalid bug, with a brief explanation.</p><p>To explain, here's what's happening:</p><p>Ned Batchelder (the poster of that blog post) came across this piece of code that worked differently in IE and Firefox.</p><code><pre>function really() { alert("Original"); }<br />if (0) {<br /> alert("No");<br /> function really() { alert("Yes, really"); }<br />}<br />really();</pre></code><p>The explanation is pretty simple. A function <code>really</code> is defined which alerts "Original". Inside an <code>if</code> block which should never get called, the <code>really</code> function is redefined to alert "Yes, really". Since the code block is inside an <code>if</code> that should never get called, the assumption would be that the function shouldn't get redefined. This is how Firefox behaves. However, not so with IE, which redefines the function. Weirdly, the alert("No"); is never executed, even though the function gets redefined.</p><p>Turns out, IE is not the only one doing this. All webkit browsers and Opera also exhibit this behavior. <a href="http://askawizard.blogspot.com/">Kris Kowal</a> was the first to suggest that this is a bug in Firefox for the right reasons. So, a bug report was created and BE closed it. Here's his explanation:</p><blockquote>ECMA-262 Edition does not specify functions in sub-statements, only at top level in another function or a program (see the normative grammar). Therefore this bug is invalid as summarized.<br /><br />Moreover, we have extended ES3 (as allowed by its chapter 16) for ~ten years to support "function statements" whose bindings depend on control flow. So this again is invalid. There's a bug to dup against, if someone finds it feel free to change resolution accordingly.<br /><br />/be</blockquote><p>For those who didn't understand, here's a simpler version of what BE said.</p><ul><li><code>function really() { ... }</code> is a <em>function declaration</em>.</li><li>Function declarations can only exist at the top level, or inside other functions. They cannot be inside the <code>if</code> statement.</li><li>If the browser finds that it is inside the <code>if</code> block, the browser is not allowed to throw an error. Instead, it should handle it gracefully.</li><li>There's no spec that defines how such situations should be handled, so browsers are free to do what they want to.</li><li>All browsers except Firefox first scan the code at load time to find function declarations. When doing so, they look at the function first, and then it's redefinition. In this case, the original function should be discarded, and the new function should be used.</li><li>Firefox does this at runtime, evaluating the functions when the code execution sees it. Hence Firefox doesn't redefine the function at all.</li></ul><p>So, BE's explanation that this is not a bug is valid. This is a gray area in the spec, and the browser is free to implement it the way it wants.</p><p>Also, and more interestingly, BE brings up <em>function statements</em> which do not follow this rule. A function statement would look like this:</p><code>var really = function() { ... };</code><p>Now, the spec very clearly says that function <em>statements</em> should be evaluated at runtime based on control flow - stuff like that <code>if</code> statement. Ned wouldn't have run into this problem if he was using function statements.</p><p>I learn new things about JavaScript every day!</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-6517290904637743323?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com1tag:blogger.com,1999:blog-8112154.post-71338766308604796102008-11-21T22:22:00.004+05:302008-11-22T03:40:16.732+05:30HTTP cache optimization<p>You know what else Twitter is good for? Quotations. As good friend and colleague, <a href="http://pranjan.blogspot.com/">Piyush Ranjan</a> <a href="http://twitter.com/piyush_ranjan/status/1015227467">said</a>:</p><blockquote>Recession is [a] good time for innovation. Best innovation happens in crunch situations. Otherwise people just throw money at the problem!</blockquote><p>At <a href="http://www.cleartrip.com/">Cleartrip</a>, as with any other company, we're always looking for ways to reduce our costs. Now with the travel industry in India hit hard, and the general economic slowdown, it's very interesting for us techies to innovate in ways that will help us cut costs.</p><p>One the recent things we've been working on, and the stuff I want to talk about here, is the area of bandwidth savings. The benefits of bandwidth savings are usually twofold. Firstly and obviously, it reduces our bills. Secondly, it usually manifests itself as a better experience for the user, since he doesn't have to wait as long for stuff to transfer from our servers to his browser every time he moves between pages.</p><p>Now, our site is a fairly dynamic site. Almost every page in the site (well, the significant ones at least), are so dynamic, they cannot even be cached for a couple of minutes. So, caching HTML doesn't suit us. What we <i>can</i> cache is everything else - images, CSS and JavaScripts. Also, since we try to adhere to web standards as much as possible while being as <i>Web 2.0</i> as possible (whatever that means), our use of CSS and JavaScripts is pretty heavy.</p><h2>Phase 1</h2><p>So, a couple of months ago, we made our first set of optimizations. We noticed that our images change very rarely - some of them hadn't changed since we first made them. There was no point sending down copies of the images to our users frequently. These could be cached pretty aggressively. We decided on an arbitrary time of 1 month for the caching of images.</p><p>Next came the JavaScript and the CSS. This posed a considerable problem. We keep doing JS and CSS changes very frequently on our site - as frequently as a couple of times a day. We couldn't afford to have them aggressively cached at the client end. We needed the agility to update our users' cache with the new versions of our code. Again, arbitrarily, we decided that the cache time for JS and CSS files would be 2 hours. That way, it wouldn't be in users' cache very aggressively, while remaining in his cache for about the length of his usage session. At the same time, it would take at most 2 hours for our changes to propagate to all users.</p><p>So, with this configuration change rolled out (it's not at all hard to do if you <a href="http://tomayko.com/writings/things-caches-do">understand caches</a> well) we sat back and monitored our savings. Turns out, the savings were pretty amazing. Hrush, our founder, even <a href="http://blog.cleartrip.com/journal/2008/11/19/cache-basics.html">blogged</a> about how our data center providers were surprised to the extent that they said that it was "just not possible" that we have such low bandwidth consumption for the traffic we get!</p><h2>The problems</h2><p>How ironic our data center guys said that, because just around that time, we were looking at how we can optimize bandwidth usage even more. And why did we decide to optimize further?</p><ul><li>Because you can</li><li>Some of our files never changed at all - core JS libraries, for example. Why bother downloading them again after 2 hours?</li><li>Because this setup was hard to work with. Remember I said we patch stuff to production very frequently? That it takes two hours to propagate meant that if it was a bug fix, it might be broken for two hours even after we've put up the patch.</li><li>Because it gets very hard to make changes that have dependencies with other resources. For example, if the JS needs certain CSS changes, and certain markup changes, in what order do you put the changes up on the server?</li></ul><p>This usually meant that we had to plan in advance and we would still have some backwards-compatibility cruft in our JS to manage this 2 hour transition. Sometimes it would take an entire day to make even a minor patch since it had to be batched with breaks of two hours. One quick-fix would be to rename the file and all references to it, but it's easy to see how painful that is to do on a file-by-file basis, not to mention that we'd run out of file names pretty soon!</p><h2>Phase 2</h2><p>One thing for sure, though. If we could somehow manage the file name issue, we can solve all the problems I listed out. That's because every time we made a patch with a different file name, it would instantly be available to all users, irrespective of their cache status. This gives rise to another interesting possibility: we didn't have to restrict ourselves to the 2 hour window anymore. We could potentially increase our cache expires time to 20 years for all that matters. That should give us MUCH more saving than we get currently, and our users will download as little as necessary.</p><p>Except, we didn't know yet how to solve the file name problem gracefully. Ideally, there shouldn't be a human being deciding which files have changed, what the file names are, and going all over the place and changing them. That would make it tedious and error prone, not to mention boring. Then of course you have to think about how these file name modifications would work with source control. You don't want to mess up your clean source code management history.</p><p>The solution to the source control mess thing was rather easy. We fake the file name. Here's what we do. We take a file name and append a random number to it. This will make the client believe that the file name has changed, and will negotiate with the server for the file. Meanwhile, at the server, we could have a rewrite rule that transforms the file name to something that maps to a real file on our server. Sounds simple enough. Tried it, and it worked like a charm.</p><p>Now, to crack the real problem - how do we generate these numbers in a sensible way. The number essentially had to be such that it would never repeat (at least for any given file), it would be global in that two pages shouldn't be using different numbers for the same resource, and when the number changes it should instantly reflect site wide. Now that we knew how the number should behave, the quest was on to come up with a mechanism to generate these numbers.</p><h2>The solution</h2><p>After a lot of thinking, we had a shameful duh moment, and it suddenly all made sense. We didn't need to invent these numbers at all. We just needed to use our source-control revision numbers! The revision numbers match all the characteristics of the number we want. Why bother with complex systems to generate and track numbers when it was already available, even if very disguised.</p><p>I'll save you the implementation details about how we made this available site wide, and how we made it possible to have instant global changes to this number. That definitely wasn't the tough part, and I'm sure you'll figure out the details. Who knows, maybe Piyush might just release a plugin for Rails to do it automatically for you. However what surprises me is that it's very hard to find such gems of knowledge on the net. I'm now beginning to think that maybe this design pattern should be used for distribution of all static resources on the web. We're definitely not the first to <q>invent</q> this pattern - why is no one else talking about it?</p><p>We've only just rolled this out on <a href="http://www.cleartrip.com/">cleartrip.com</a> and are still to get a decent sample of data to see how it has impacted our bandwidth consumption. But any fool could guess that our bills should reduce significantly with this change.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7133876630860479610?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-43419990194056753052008-11-12T14:48:00.003+05:302008-11-12T14:57:51.108+05:30Joel on Project Managers<p>This quote is long, in typical <a href="http://www.joelonsoftware.com/">Joel On Software</a> style. He said this in his <a href="http://blog.stackoverflow.com/2008/11/podcast-28/">latest podcast</a> over at <a href="http://www.stackoverflow.com/">Stack Overflow</a> with <a href="http://www.codinghorror.com/">Jeff Atwood</a>. I've ripped it off the <a href="https://stackoverflow.fogbugz.com/default.asp?W25972">transcript wiki</a>. Definitely worth a read.</p><blockquote>Here's my feeling about project managers:<br /><p>One of the things that is interesting is that project managers, traditionally, are brought on because you have a team of yahoos - and this is just as true in construction, or in building an oil rig, or in any kind of project as it is in the making of anything - making a new car at general motors, or designing the new Boeing 787 dream liner - as it is in the software industry. Project managers are brought in because management says: "Hey, you yahoos! You're just working and working and working and never get the thing done and nobody knows how long it's going to take." If you don't know how long something's going to take and you can't control that a little bit then this really sucks from a business perspective. I mean; if you think of a typical business project - you invest some money and then you make some money back. The money you make back - the return on investment - might be double the amount of money you invest and then it's a good investment. But if the investment doubles because it took you twice as long to do this thing as you thought it would then you've lost all your profit on the thing. So this is bad for businesses to make decisions in the face of poor information about how long the project is going to take and so keeping a project on track and on schedule is really important.</p><p>It's so important that they started hiring people to do this and they said: "OK, you're the project manager - make sure that we're on track." These project managers were just bright college kids with spreadsheets and Microsoft project and clipboards. They pretty much had to go around with no authority what so ever and walk around the project and talk to the people and find out where things were up to and they spent all their time creating and maintaining these gigantic gantt charts - which everybody else ignored. So the gantt charts, and the Microsoft project, and all those project schedules, and all that kind of stuff, was an artifact created by a kind of low level person. Although it might be accurate depending on how good that low level person was, but it was still an output only thing from the current project: Where are we up to? What have we done? How much time have we spent? What's left? Who is working on what?</p><p>Then, for some reason, these relatively low level people, who were not actually domain experts, (if they were at Boeing they don't know anything about designing planes, if they were on the software team they're not programmers - they're project managers, and they don't know anything about writing code) they start getting blame when things went wrong and they started clamoring for more responsibility, more authority to actually make changes and to actually influence things and say: "Hey, Joe's taking too long here - we should get Mary to do this task, she's not busy." The truth is that they started getting frustrated because they were low level secretarial-like members of their teams and they wanted to move their profession up the scale so they created the project management institute - or whatever it's called - and they created this thing called... ah, I don't even know! But they created a whole professional way to learn to be a professional project manager and they decided to try to make it something a little bit fancier than just the kid with the clipboard that has to maintain these gantt charts all day long. You can tell this is what happened because the first thing project managers will tell you about their profession is that the most important thing is that they have the authority to actually change things and that they are the ones that actually have all the skills that can get a project back on track, or to keep a project on track, and therefore they need to have the authority to exercise these skills otherwise they'll never get anything done, they'll never be able to keep the project on track, they don't just want to be stenographers writing things down.</p><p>The trouble is, they don't actually have the domain skills - that's why they are project managers. If you are working on a software project you know how to bring it in on time and you've got to cut features, and you know which features to cut, becuase you understand software intrinsically and you know what things are slow and what things are fast and where you might be able to combine two features into one feature, where you might be able to take a shortcut. That's the stuff a good developer knows, that's not the stuff a project manager knows. In a construction project it's the architects and the head contractors who know where shortcuts can be taken and how to bring a project in on time not the project manager. The project managers don't have any of the right skills to affect the project and so they inevitably get really frustrated and everybody treats them like secretaries, or treats them like 'annoying boy with clipboard', when they really don't have a leadership role in the project - and they're not going to be able to because they don't have the domain expertise. No matter how much they learn about project management, no matter how many books they read, or how many certificates they get, no matter how long they've been doing project management: if they don't know about software, and software development, if they don't have that experience, they are always going to be second class citizens and they're never going to be able to fix a broken project.</p></blockquote><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-4341999019405675305?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-1993433699666849242008-10-08T21:46:00.010+05:302008-10-10T02:13:31.541+05:30Understanding eval scope. Spoiler: It's unreliable!<p>Today, I ran some tests to help me understand the scope in which an eval runs. Turns out, like so many things in the browser world, it's very unpredictable and exhibit different behaviors in different browsers.</p><p>Let's start with the following snippet of code. I've added comments to demarcate areas in the code, which I will be changing with each iteration.</p><p><code><pre><br />var foo = 123;<br />var bar = {<br /> changeFoo: function() {<br /> // We'll keep changing the following snippet<br /> alert(this);<br /> eval("var foo = 456");<br /> // Changing snippet ends<br /> }<br />};<br /><br />bar.changeFoo();<br />alert(foo);<br /></pre></code></p><p>A little explanation of the code above. <code>foo</code> is a variable in the global scope, and it's value is set to 123. An object <code>bar</code> is created with a single method <code>changeFoo</code> which does an <code>eval</code>. The <code>eval</code> creates a local variable (thanks to the <code>var</code>) <code>foo</code>, and sets it's value to 456. <code>bar.changeFoo</code> is called, and the value of the global <code>foo</code> is <code>alert</code>ed.</p><p>The aim is to test the scope in which <code>eval</code> runs. If <code>eval</code> is in the global scope, the global variable <code>foo</code> should change it's value. If <code>eval</code> is in the local scope, the global <code>foo</code> should be unaffected. Then there are various things we can do inside the <code>changeFoo</code> method which should keep altering the scope of <code>this</code>, so we are also alerting <code>this</code> to see what happens.</p><p>The findings are listed below:</p><table width="100%" style="text-align: center;"><thead style="background: #bbb;"><tr><th style="text-align: center;">&nbsp;</th><th style="text-align: center;">Changed snippet</th><th colspan="2">Internet Explorer</th><th colspan="2">Safari 3.x</th><th colspan="2">Firefox</th><th colspan="2">Google Chrome</th><th colspan="2">Safari Nightlies</th></tr><tr><th style="text-align: center;">&nbsp;</th><th style="text-align: center;">&nbsp;</th><th style="text-align: center;">foo</th><th style="text-align: center;">this</th><th style="text-align: center;">foo</th><th style="text-align: center;">this</th><th style="text-align: center;">foo</th><th style="text-align: center;">this</th><th style="text-align: center;">foo</th><th style="text-align: center;">this</th><th style="text-align: center;">foo</th><th style="text-align: center;">this</th></tr></thead><tbody><tr><td valign="top">1</td><td><code><pre style="text-align: left">alert(this);<br />eval("var foo=456");</pre></code></td><td>123</td><td>object</td><td>123</td><td>object</td><td>123</td><td>object</td><td>123</td><td>object</td><td>123</td><td>object</td></tr><tr style="background: #eee;"><td valign="top">2</td><td><code><pre style="text-align: left">alert(this);<br />window.eval("var foo=456");</pre></code></td><td>123</td><td>object</td><td>123</td><td>object</td><td>456</td><td>object</td><td>123</td><td>object</td><td>456</td><td>object</td></tr><tr><td valign="top">3</td><td><code><pre style="text-align: left">alert(this);<br />this.eval("var foo=456");</pre></code></td><td>error</td><td>object</td><td>error</td><td>object</td><td>error</td><td>object</td><td>error</td><td>object</td><td>error</td><td>object</td></tr><tr style="background: #eee;"><td valign="top">4</td><td><code><pre style="text-align: left">alert(this);<br />eval("var foo=456", window);</pre></code></td><td>123</td><td>object</td><td>123</td><td>object</td><td>456</td><td>object</td><td>123</td><td>object</td><td>123</td><td>object</td></tr><tr><td valign="top">5</td><td><code><pre style="text-align: left">(function() {<br /> alert(this);<br /> eval("var foo=456");<br />})();</pre></code></td><td>123</td><td>object</td><td>123</td><td>window</td><td>123</td><td>window</td><td>123</td><td>object</td><td>123</td><td>window</td></tr><tr style="background: #eee;"><td valign="top">6</td><td><code><pre style="text-align: left">(function() {<br /> alert(this);<br /> window.eval("var foo=456");<br />})();</pre></code></td><td>123</td><td>object</td><td>123</td><td>window</td><td>456</td><td>window</td><td>123</td><td>object</td><td>456</td><td>window</td></tr><tr><td valign="top">7</td><td><code><pre style="text-align: left">with(window) {<br /> alert(this);<br /> eval("var foo=456");<br />}</pre></code></td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td></tr><tr style="background: #eee;"><td valign="top">8</td><td><code><pre style="text-align: left">with(window) {<br /> alert(this);<br /> window.eval("var foo=456");<br />}</pre></code></td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td><td>456</td><td>object</td></tr></tbody></table><br /><p><strong>What I think of these results</strong>: <ul><li>I don't know what Firefox is doing in case 2, and for some reason Safari Nightlies seem to be following it. Maybe it's just beyond my understanding, but case 2 is not supposed to be different from case 1. Why does case 2 operate in global scope? If <code>window.eval</code> is different from <code>eval</code>, case 3 shouldn't all have given errors. Someone please help me understand that $hit.</li><li>Case 4 makes sense, but that's a non-standard behavior in Firefox. Understandable that no one else exhibits it.</li><li>IE baffles me in case 5, and Chrome seems to ape it. In this scenario, the anonymous function is supposed to have the global scope - so, in this case, <code>this</code> should point to the window. WTF is happening here!</li><li>Consistent with case 2 above, Firefox and Safari Nightlies continue to display weird behavior in case 6. For some reason, in these two cases, the <code>eval</code> operates in the global scope.</li><li>Now, I have no idea why, but only cases 8 and 9 seem to really work at all. This is despite Doug Crockford going on and on about not using <code>with</code> constructs. It's also despite being beyond (my) understanding about why the <code>with</code> should make any difference to the <code>eval</code>, since <code>eval</code> is part of the window object.</li></ul><p>All in all, if you are going to be <code>eval</code>ing JavaScript (not JSON), and you want the eval'd code to run in the global scope, you should use the <code>with</code> block around the JavaScript snippet. Or else, you can lose a lot of hair handling cross-browser issues.</p><p>Hope you don't lose as much hair as me.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-199343369966684924?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com13tag:blogger.com,1999:blog-8112154.post-50900300037414926402008-09-17T23:28:00.002+05:302008-09-17T23:42:44.961+05:30Housekeeping<p>I've done a couple of minor changes to this blog's UI. Nothing dramatic, but I thought I should draw your attention to it, especially if you are one reading only from my <a href="http://piecesofrakesh.blogspot.com/feeds/posts/default" title="My Atom Feed">Atom</a>/<a href="http://piecesofrakesh.blogspot.com/feeds/posts/default?alt=rss" title="My RSS Feed">RSS</a> feed.</p><p>The first change came from realizing that my posts are longer than they should be. Somehow, I can't seem to compress them beyond what I already do. Long pages are a pain the wrong spots to read, so I decided to expand Douglas Bowman's original layout to a fluid width page, so that my posts consume lesser vertical space. (I just noticed that <a href="http://steve-yegge.blogspot.com/" title="Stevey's blog">Steve Yegge</a> has done similar fixes - I'm flattered.)</p><p>Secondly, and sort of to compensate for my lowered rate of posting on this blog, I've included two new feeds you can subscribe to on this blog. You can find latest updates to these feeds in the right sidebar. First is <a href="http://del.icio.us/rss/rakeshpai/">my feed from del.icio.us</a>, which happens to be my bookmarking service of preference. Secondly, is <a href="http://www.google.com/reader/public/atom/user/14713094510129037345/state/com.google/broadcast">my list of shared RSS feeds from my Google Reader</a>. Both of these feeds get updated more frequently than my blog itself, so you might find these interesting.</p><p>This way, not only do you keep in touch with what I'm writing, you can also keep in touch with the stuff I'm reading. Expect to find some tech humor in these feeds too ;). Here's the rule of the thumb: The two new feeds reflect what I'm thinking strongly about, but I do not necessarily have an opinion about. My blog is my list of opinions. That's the difference.</p><p>I've been testing these thingies on my blog for some time now, so if you've been around here recently, you might have already noticed these changes. I just thought I'd wait a bit before I can announce these new things - turns out Google is doing a reasonable job of ensuring these things work, after all. ;)</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-5090030003741492640?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-75821162652852198182008-09-03T14:25:00.004+05:302008-09-03T16:55:20.432+05:30JavaScript for Linux Hackers<p>Two weekends ago (24 August), I gave a talk about JavaScript at the <a href="http://www.ilug-bom.org.in/">Indian GNU/Linux Users Group of Mumbai (ILUG-BOM)</a> - A small gathering of Linux hackers from around the city. The talk was held at the <a href="http://www.hbcse.tifr.res.in/">Homi Bhabha Centre for Science Education (HBSCE)</a>, <abbr title="Tata Institute of Fundamental Research">TIFR</abbr>, Mumbai.</p><p>It was very weird having to explain JavaScript to kernel hackers and sysadmins. It entails a different approach - one where you have to assume that the audience knows a lot already, probably more than you in some respects. They are not one to get wowed by browser effects and visual fanciness. Also I know very little about Linux systems, so we had very little in common. It's very challenging preparing for such an audience.</p><p>I spoke about the language, it's history, it's expressiveness, the type system, variable casting, objects, marshaling objects, it's lambda nature, and several language constructs, especially functions. What I didn't cover was things like the DOM, inheritance patterns and constructor functions, but there has to be something for next time, right? ;)</p><p>I think it went pretty well. Well enough for them to invite me for another session where we could cover the left-out topics. I'm sorry - I would have put my slides on slideshare or something, but honestly, when I was running through my slideshow the day before the presentation, I nearly dozed off. So I decided that I'd just do the presentation without the slides - just me talking, and a JavaScript console on the screen.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7582116265285219818?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com2tag:blogger.com,1999:blog-8112154.post-48835327774067474562008-08-29T20:48:00.005+05:302008-08-29T21:44:41.047+05:30element.hasFocus? document.activeElement!<p>Today at work, in some code I was writing, I wanted to know if a given <code>input</code> box has focus or not. Turned out, this is surprisingly difficult. The input element doesn't have any <code>hasFocus</code> or similar property! No wonder working with the DOM keeps tripping people up!</p><p>Turns out, from quite some time now, Internet Exploder has been supporting a proprietary property - <code><a href="http://msdn.microsoft.com/en-us/library/ms533065(VS.85).aspx">document.activeElement</a></code> - which tells you which element is current focussed. Exactly what I needed. Except this is proprietary - I tried in Firefox 2, and it didn't work as expected. However, fortunately, turns out <a href="http://www.whatwg.org/specs/web-apps/current-work/#focus-management">the HTML 5 spec has now incorporated this new property</a> of the <code>document</code> object, and all future browsers should support it. <a href="http://developer.mozilla.org/En/DOM:element.activeElement">Firefox 3 already supports <code>document.activeElement</code></a>. I've read that Opera supports it, but haven't tried. Safari does not, but the latest nightlies support it as well. Of course IE6 and IE7 support it perfectly well - IE invented it after all. So, of the big browsers, only Firefox 2 and Safari are problematic.</p><p>Since my code was not super critical, I've decided to skip support for just this bit for Firefox 2 and Safari. In any case, I'm hoping (against hope?) that both these browsers have a faster upgrade cycle than others, so they'll be outdated pretty soon.</p><p>Just in case you were thinking that the focused element can easily be 'discovered' by using the onblur and onfocus events, think again. Firstly, according to the specs, <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html">the focus and blur events don't bubble</a>, so you can't use <a href="http://www.google.co.in/search?q=javascript+event+delegation&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a">event delegation</a> to capture all focus/blur events on the document. In any case, if you could use event delegation, putting these event handlers in an external script would mean that the script will kick in after a little delay - either after the script has loaded if the script tag is placed at the bottom, or after the page load happens if you are waiting for the DOM to be ready before you can use it, which in my case wasn't acceptable. The only other solution is to have a script include or a inline script tag that declares a function before the DOM is loaded, and then have inline onblur and onfocus event handlers <a href="http://en.wikipedia.org/wiki/DOM_Events#DOM_Level_0">DOM Level 0 style</a>. That's just plain ugly. None of these solutions are either workable or graceful.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-4883532777406747456?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com2tag:blogger.com,1999:blog-8112154.post-57768365215732399002008-08-13T21:28:00.003+05:302008-08-13T21:43:42.169+05:30Brendan Eich on code translation to JavaScript<p>I've always hated the idea of some server-side language (like ASP.Net, GWT, RoR, what-have-you) generating JS code to run on the client. I'm glad at least Eich agrees with me, as is published in <a href="http://www.computerworld.com.au/index.php/id;243672124;fp;;fpid;">this interview</a>. (Jump to <a href="http://www.computerworld.com.au/index.php/id;243672124;pp;3;fp;;fpid;">page 3</a> for this excerpt.)</p><blockquote><p>I did not intend JS to be a "target" language for compilers such as Google Web Toolkit (GWT) or (before GWT) HaXe and similar such code generators, which take a different source language and produce JS as the "object" or "target" executable language.</p><p>The code generator approach uses JS as a "safe" mid-level intermediate language between a high-level source language written on the server side, and the optimized C or C++ code in the browser that implements JS. This stresses different performance paths in the JS engine code, and potentially causes people to push for features in the Ecma standard that are not appropriate for most human coders.</p><p>JS code generation by compilers and runtimes that use a different source language does seem to be "working", in the sense that JS performance is good enough and getting better, and everyone wants to maximize "reach" by targeting JS in the browser. But most JS is hand-coded, and I expect it will remain so for a long time. </p></blockquote><p>That said, I think Eich doesn't highlight some of the other problems with server-generated JavaScript: ability to debug, potentially unoptimized output, and potentially inefficient code. I've worked with server-generated JavaScript in ASP.Net and RoR, and I know what a pain it can be.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-5776836521573239900?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com1tag:blogger.com,1999:blog-8112154.post-74657241568433620732008-06-20T14:59:00.004+05:302008-06-20T15:25:39.686+05:30IE Congratulates Firefox... on shipping Firefox 3.0.<br /><div style="text-align: center"><a href="http://www.flickr.com/photos/robceemoz/2587912633/"><img src="http://farm4.static.flickr.com/3122/2587912633_9084fecde4.jpg?v=0" /></a></div><br />The comments from around the web are hilarious:<ul><li>Don't eat it.</li><li>Is it not poisoned?</li><li>That cake will give you CSS rendering errors, in your colon.</li><li>Moments later the cake hit a knife/plate standard it wasn't compliant with.</li><li>It must have been hard for them to put "love" on the cake </li><li>As you eat away the icing, you'll see that the cake is blue... little by little, it's becoming clear... it's the blue screen of death!</li><li>Congratulations on shitting the IE7 Team </li><li>...did it come with an End User License Agreement...?</li><li>There should be some bugs inside the cake.</li><li>...it's probably half baked too!</li><li>I guess that box was rendered in quirks mode.</li><li>Sheesh, even their cake has box model bugs.</li><li>I was wondering what the IE team had been doing for the past 3 years...</li><li>There's actually an IE team?</li><li>[Apple] snuck their cake through during the last Quicktime update.</li><li>And if you didn't like the candles, you had to replace the whole cake.</li><li>...that the cake tasted pretty good, but as they started to dig in, they sadly realized that instead of a whole cake, they had actually gotten a thin layer of cake on top of a cake-shaped support structure made of toothpicks and glue.</li><li>Turns out they forgot to add sugar to the cake. That will be added on Patch Tuesday.</li><li>Good luck getting the recipe for that cake.</li></ul><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7465724156843362073?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com1tag:blogger.com,1999:blog-8112154.post-70207044119010592862008-06-10T19:24:00.003+05:302008-06-10T19:49:56.950+05:30Simply use HTML. Not XHTML.<p>The good 'ol argument about HTML vs. XHTML seems to have resurfaced on the <a href="http://en.wikipedia.org/wiki/Internets">Internets</a>. I have been firmly <a href="http://piecesofrakesh.blogspot.com/2004/09/economics-of-xhtml.html">in the XHTML camp</a> at one time, but I had made a mention <a href="http://piecesofrakesh.blogspot.com/2007/09/much-deserved-update.html">in a previous post</a> about why I think that there was no point in fighting this battle anymore. There is a clear winner - HTML.<p><p>Of the lot of recent posts out there about which is better than the other, this little <a href="http://diveintomark.org/archives/2004/01/14/thought_experiment">thought experiment</a> echoes my sentiments about XHTML vs. HTML.</p><blockquote>You pore through the raw source code of the page and find what you think is the problem, but it’s not in your content. In fact, it’s in an auto-generated part of the page that you have no control over. What happened was, someone linked to you, and when they linked to you they sent a trackback with some illegal characters (illegal for you, not for them, since they declare a different character set than you do). But your publishing tool had a bug, and it automatically inserted their illegal characters into your carefully and validly authored page, and now all hell has broken loose.<br /><br />The emails are really pouring in now. You desperately jump to your administration page to delete the offending trackback, but oh no! The administration page itself tries to display the trackbacks you’ve received, and you get an XML processing error. The same bug that was preventing your readers from reading your published page is now preventing you from fixing it!</blockquote><p>The fact is today's web is one where content might pour in from various locations, many of which you might not have control over. It is important to inter-operate with these kinds of content sources. Expecting strictness from an external source is not only overkill, it's folly to do so.</p><p>I had faced this problem when I had worked on the <a href="http://www.nba.com/kings/">Sacramento Kings website</a>. The content was coming from various sources, some even as trustworthy (for them at least) as the NBA. However, content encoding and ill formed markup issues were huge enough to get <a href="http://piecesofrakesh.blogspot.com/2007/02/ies-unknown-runtime-error-when-using.html">the JavaScript all crazy</a>. I can't even imagine the amount of problems I'd have faced if we'd have decided to use a XHTML strict, or even transitional, doctype for this job. How can we force a content author to ensure that his content validates, and that the reference validation for your site and the reference validation for the content author is the same?</p><p>Simply use HTML. Let the onus of making sense of the content lie with the browser. It's not a human's job to make content appealing to a computer. If a computer cannot understand it, it should work hard. Not the human.</p><p>Just for the humor, check out this page that a friend happened to hit when pulling up <a href="http://www.w3.org/">W3.org</a> the other day. I know I'm being harsh when I say this, but the guys who made the standard can't seem to respect it.</p><div style="text-align: center"><a href="http://www.flickr.com/photos/rakesh/2567088677/" title="W3 Parsing Error by Rakesh Pai, on Flickr"><img src="http://farm3.static.flickr.com/2302/2567088677_57540dea3d.jpg" width="500" height="133" alt="W3 Parsing Error" /></a></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7020704411901059286?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-12227850520591339982008-06-03T15:48:00.004+05:302008-06-03T15:56:41.855+05:30GoaJust got back from a trip to Goa with colleagues. Here are some of the pics:<br /><p style="text-align: center"><a href="http://www.flickr.com/photos/rakesh/2544698170/" title="Dog and Chair by Rakesh Pai, on Flickr"><img src="http://farm3.static.flickr.com/2153/2544698170_073a441528_m.jpg" width="240" height="180" alt="Dog and Chair" /></a><a href="http://www.flickr.com/photos/rakesh/2544697988/" title="Altar by Rakesh Pai, on Flickr"><img src="http://farm4.static.flickr.com/3009/2544697988_53502a08c2_m.jpg" width="240" height="180" alt="Altar" /></a><br /><a href="http://www.flickr.com/photos/rakesh/2543868947/" title="Resort by Rakesh Pai, on Flickr"><img src="http://farm3.static.flickr.com/2169/2543868947_1d609428bf_m.jpg" width="240" height="180" alt="Resort" /></a><a href="http://www.flickr.com/photos/rakesh/2543868849/" title="Anurag by Rakesh Pai, on Flickr"><img src="http://farm3.static.flickr.com/2162/2543868849_7a9895ca2b_m.jpg" width="240" height="180" alt="Anurag" /></a></p><br /><br /><a href="http://flickr.com/search/show/?q=goa&w=29609190%40N00">Head over to Flickr</a> for all the pics.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-1222785052059133998?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-54565491309989150872008-04-21T15:50:00.002+05:302008-04-21T16:15:17.190+05:30Getting iSync to work with the Nokia N91 8GB<p>My phone is a <a href="http://www.nokia-asia.com/A4417199">Nokia N91 8GB</a>, and my primary OS these days is the Mac OSX 10.4.11. When I followed instructions I could find anywhere on the web - the simple connect, launch, sync instructions - it simply didn't work. iSync kept complaining that it couldn't sync with my device.</p><p>That just meant it's time to get under the hood and do some hacking! If you ever face this problem, here's how you solve this issue.</p><ul><li>Quit iSync if you already have it open.</li><li>Go to your applications folder, right-click on the iSync application icon, and select "Show Package Contents".</li><li>Keep clicking through to the following path: Contents/PlugIns/ApplePhoneConduit.syncdevice/Contents/Plugins/Nokia-N91.phoneplugin/Contents/Resources.</li><li>Once there, duplicate the MetaClasses.plist file just to have a backup. You can do that by right-clicking the file, and selecting "Duplicate".</li><li>Now, open the file with a text editor - I used TextWrangler, and search for the line that says <code>&lt;key&gt;com.nokia.n91&lt;/key&gt;</code>. A little lower, you should find a &lt;key&gt;Identification&lt;/key&gt;. Right below that should be a &lt;dict&gt; XML node.</li><li>Edit it to look as follows:<br /><pre style='color:#000000;background:#ffffff;'><span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>dict</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>key</span><span style='color:#a65700; '>></span>com.apple.usb.vendorid-modelid<span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>key</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span>0x0421/0x042F<span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>key</span><span style='color:#a65700; '>></span>com.apple.gmi+gmm<span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>key</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>array</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span>Nokia+Nokia N91-1<span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span>Nokia+Nokia N91-2<span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>string</span><span style='color:#a65700; '>></span><br /> <span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>array</span><span style='color:#a65700; '>></span><br /><span style='color:#a65700; '>&lt;/</span><span style='color:#5f5035; '>dict</span><span style='color:#a65700; '>></span><br /></pre></li></ul><p>That's it - you are set. Now, launch iSync and it should now be able to work with your N91 8GB as advertised.</p><p>The key here is that the N91 8GB model is identified as Nokia+Nokia N91-2, which isn't available in the supported devices list by default - the regular N91 is identified as Nokia+Nokia N91-1 or simply Nokia+Nokia N91, which is supported. The hack just adds support for the N91 8GB by telling iSync to treat it as the Nokia+Nokia N91-1 for all practical purposes.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-5456549130998915087?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com3tag:blogger.com,1999:blog-8112154.post-48671504380345998812008-02-28T14:08:00.002+05:302008-02-28T14:37:30.783+05:30Web 2.0 ProfessionalsGot this job offer in my mail today:<br /><blockquote>COMPANY: [Company Name] ...with a reputation of being a leading supplier of networking equipment and network management for the Internet.<br /><br />LOCATION: Bangalore<br /><br />JOB OVERVIEW: We are looking for <strong>Senior Web.20 professionals</strong> on a very Urgent basis. Person with good relavant experience is most preferable.<br /><br />EXPERIENCE: Min. 4 yrs to 12 yrs<br /><br />POSITION: Permanent<br /><br />If you a are looking for a change then plz fwd your updated word formatted (*.doc) CV to me ASAP with following details:<br /><br />[snip]<br /><br />5. Experience in Web 2.0<br /><br />[snip]<br /></blockquote><p>Typos and poor language apart, can someone please explain what a <i><q>Web 2.0 Professional</q></i> is? What does he do? How in the world is he supposed to have 4 to 12 years experience? And how can he give <q>details</q> of his <q>Experience in Web 2.0</q>? Not to mention, I am very curious about how Web 2.0 is relevant to <q>a leading supplier of networking equipment and network management for the Internet</q>.</p><p>I guess this just shows that we are at the peak of the hype.</p><p>Some where in a board room:<br /><q>How do we boost sales of our NICs and routers?</q><br /><q>What we really need is some Web 2.0 action going for us.</q><br /><q>What is that?</q><br /><q>Don't you know? Everyone's talking about it. It's the greatest thing to have happend!</q><br /><q>Ok. Get HR to find a Web 2.0 Professional. Make sure he has a decent amount of experience.</q></p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-4867150438034599881?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com1tag:blogger.com,1999:blog-8112154.post-76437810362126612512008-01-29T13:01:00.000+05:302008-01-29T13:14:22.244+05:30On X-UA-Compatible<p>There's been so much said about this...</p><ul><li>Chris Wilson <a href="http://blogs.msdn.com/ie/archive/2008/01/21/compatibility-and-ie8.aspx">spells out the need for it</a>.</li><li>Aaron Gustafson <a href="http://www.alistapart.com/articles/beyonddoctype">explains the details on A List Apart (!)</a>.</li><li>Eric Meyer <a href="http://www.alistapart.com/articles/fromswitchestotargets">welcomes it</a>.</li><li><a href="http://snook.ca/archives/browsers/version_targeting_ie8/">So does Jonathan Snook</a>.</li><li>Anne Van Kesteren thinks <a href="http://annevankesteren.nl/2008/01/ie-lock-in">it's an IE lock-in all over again</a>.</li><li>Mozilla devs <a href="http://weblogs.mozillazine.org/roc/archives/2008/01/post_2.html">have questions</a>.</li><li>PPK <a href="http://www.quirksmode.org/blog/archives/2008/01/the_versioning.html">observes quitely</a>.</li><li>WaSP guys clarify that <a href="http://www.webstandards.org/2008/01/22/microsofts-version-targeting-proposal/">they were not necessarily involved, though MS claims so</a>.</li><li>Jeremy Keith thinks <a href="http://adactio.com/journal/1402/">MS's got it backwards</a>.</li><li>Andy Budd thinks <a href="http://www.andybudd.com/archives/2008/01/has_internet_ex/">IE just shot itself in the foot</a>.</li><li>Jeffery Zeldman <a href="http://www.zeldman.com/2008/01/22/in-defense-of-version-targeting/">defends the idea anyway</a>.</li><li>John Resig thinks <a href="http://ejohn.org/blog/meta-madness/">the trouble is worthless</a>.</li><li>Dean Edwards <a href="http://dean.edwards.name/weblog/2008/01/quotes/">sits on the fence and snickers</a>.</li><li>Roger Johansson is <a href="http://www.456bereastreet.com/archive/200801/standards_mode_is_the_new_quirks_mode/">not convinced that it's a good idea</a>.</li><li>Rachel Andrew thinks <a href="http://www.rachelandrew.co.uk/archives/2008/01/22/ie8-and-the-future-of-the-web/">this is a step backwards</a>.</li><li>Safari says <a href="http://webkit.org/blog/155/versioning-compatibility-and-standards/">they are not going to implement it</a>.</li><li>Ian Hickson thinks <a href="http://ln.hixie.ch/?start=1201080691&count=1">MS is going to be in trouble</a>.</li><li>Mike Davies says that <a href="http://www.isolani.co.uk/blog/standards/EndOfLineInternetExplorer">it's the end of the line for IE</a>.</li></ul><p>... that if I write an opinion piece, it will go unnoticed.</p><p>So, what do I think anyway? If this is MS's only chance at fixing the web, I love the idea. However, this is a drastic step, and MS cannot botch this up. If they do, no one will want to work for their browser anymore. If no sites are written for their browser, users won't use their browser anymore. As a front-end developer, having to cater to three different browser types (IE6, IE7 and good browsers) with HUGE differences between them, is already a pain in the wrong spots. Adding one more to the mix will only worsen the situation. But if IE8 starts actually behaving like the good browsers, we can finally hope that all our problems will vanish with IE6 and IE7 - whenever that happens.</p><p>So, if MS thinks that this is the solution to all their problems, so be it. The world will comply this one last time. This is a lot of trouble. It better be worth it. If this ends up having a less-than-desirable result, MS is doomed. IE is doomed. And the web will be a better place anyway, IE or otherwise.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7643781036212661251?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-90455529684115876592008-01-24T21:27:00.000+05:302008-01-24T21:28:52.968+05:30Bill G Has Left The Building<div style="align: center"><object width="425" height="355"><param name="movie" value="http://www.youtube.com/v/Xr5w3X4R8b4&rel=1"></param><param name="wmode" value="transparent"></param><embed src="http://www.youtube.com/v/Xr5w3X4R8b4&rel=1" type="application/x-shockwave-flash" wmode="transparent" width="425" height="355"></embed></object></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-9045552968411587659?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-68788589968064030222007-12-11T15:34:00.000+05:302008-01-29T21:31:21.766+05:30A Movie About Coffee<div style="text-align: center"><a href="http://www.dilbert.com/comics/dilbert/archive/dilbert-20071115.html"><img src="http://hsirkel.net/dilbert/dilbert20071115.gif" /></a></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-6878858996806403022?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com2tag:blogger.com,1999:blog-8112154.post-63944772071940137162007-11-20T01:30:00.000+05:302007-11-20T21:16:24.842+05:30How To Build A Read/Write JavaScript API<a href="http://digg.com/submit?phase=2&url=http://piecesofrakesh.blogspot.com/2007/11/how-to-build-readwrite-javascript-api.html" target="_blank" style="float: right"><img border="0" alt="Digg my article" src="http://digg.com/img/badges/91x17-digg-button.gif"/></a><p>I've learnt most of this primarily by reading through <a href="http://code.google.com/apis/gdata/client-js.html">Google Calendar's JavaScript Client Library</a> code. I've also picked up clues from <a href="http://www.xucia.com/CrossSafe/readme.html">lots</a> of <a href="http://www2007.org/program/paper.php?id=801">other</a> <a href="http://www.youtube.com/watch?v=ZvFVs92Fydw">material</a> around the Internet. There are also some minor improvements I've added.</p><p>So, here's the use-case: You probably already have a <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm"><abbr title="Representational State Transfer">REST</abbr></a> (or similar) <abbr title="Application Programming Interface">API</abbr> for server to server communication. Having a JavaScript API would be a great idea (after all, JavaScript is the most deployed programming language available on almost every platform in the form of a browser runtime). This poses many problems. Most significantly, browsers are very strict about the <a href="http://en.wikipedia.org/wiki/Same_origin_policy">same origin policy</a>. You are aware of <a href="http://snook.ca/archives/javascript/cross_domain_aj/">certain hacks out there to use JavaScript across domains</a>, but at best they give you read access or rely on browser plugins. You can do writes using query string parameters, but you know that <a href="http://www.w3.org/2001/tag/doc/whenToUseGet.html">that's just plain wrong</a>.</p><p>Whatever be your solution to this problem, you want to play within the browser's security model, and not depend on any browser-specific security loopholes. Another very important thing you want to achieve is to ensure that your API users do not have to do any setup at their end – be it in terms of installing a <a href="http://ajaxpatterns.org/archive/Cross-Domain_Proxy.php">server-side proxy</a>, or jumping through hoops of any other kind. If a setup is unavoidable, it should be very simple to do, requiring little or no effort. You might also add additional requirements of user authentication (after all, you are letting them do writes), preferably at your domain – <a href="http://openid.net/">OpenID</a> style – and have access to your cookies even when your application is being used from another domain entirely.</p><p>People might point out solutions like <a href="http://www.xucia.com/CrossSafe/readme.html">CrossSafe</a> and <a href="http://www2007.org/program/paper.php?id=801">Subspace</a>. From what I gather of both these ideas, their goal is to <a href="http://blog.360.yahoo.com/blog-TBPekxc1dLNy5DOloPfzVvFIVOWMB0li?p=715">secure your site</a> from any third-party script snippet. That is not a necessary goal in our case. Also, both these techniques rely very heavily on some form of setup at the API consumer's end (which aren't very easy to do either – may even be impossible for say shared hosting environments), which we don't want to have. The technique I'm suggesting here is very similar in it's operation to both Subspace and CrossSafe, but eliminates (or reduces drastically) the need for any setup at the user's end.</p><p><a href="http://json.org/JSONRequest.html">The JSONRequest specification</a> also needs mentioning. Unfortunately, the spec itself is rather new. Needless to say, there's no native working implementation of it as of this writing. CrossSafe comes rather close as an implementation, but <a href="http://www.xucia.com/CrossSafe/readme.html#limitations">it's not complete</a>. (To make matters worse, completing the implementation will require even more server-side co-operation at the API consumer's end.) That said, I don't know why Doug Crockford has decided to keep PUT and DELETE methods out of the spec, among others. I guess it might be for simplicity. However, I think in today's RESTful days not having those methods supported is not a good idea. If Crockford's spec ever becomes the standard, I will be a little unhappy that the additional methods are not supported. The API creation technique I'm mentioning here supports all the HTTP methods that the browser supports for HTML forms (which is <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.1">only GET and POST</a> for all major browsers to the best of my knowledge), but at least it's a browser limitation – not one imposed by this technique.<sup><a href="#moreMethods">1</a></sup></p><p>So, let's get started. Here's what you require to get cross-domain read write JavaScript APIs to work.</p><ul><li><p>The "setup" required at the client's end is that he should have at least one static cacheable resource embedded in the page where he's consuming the API, which is loaded from the same domain as his page. This could be in the form of a static CSS file, or an image. If the page doesn't have either, it will be required to insert one – maybe in the form of a 1px image hidden away by using inline style attributes. This is usually not too much to ask for, considering that pages are either made up of spacer GIFs or CSS documents, usually loaded from within the same domain. The static resources I mentioned could even be from a different sub-domain within the same domain, but it might complicate scripts slightly to have it set up that way. If this setup is not possible at all (oh, come on!), you could still find a work around<sup><a href="#domainResourceWorkaround">2</a></sup>, but I think that this is the easiest way to get things up and running.</p></li><li><p>You will need to do some setup at your end, if you are the creator of the API. In particular, you will need to setup a "proxy" page that intercepts the requests from the JavaScript client API, conditions the data, and passes it along to the REST API. This proxy page also reads the response from the REST API, conditions the data to suit the client, and flushes it down to the JavaScript.</p></li></ul><p>Now, let's go over the process of actually orchestrating the communication.</p><ol><li><p>The API client library is included on the page by means of a script tag pointing to your domain (your domain being the host of the client library). This is similar to <a href="http://www.google.com/apis/maps/documentation/index.html#AJAX_Loader">including the Google Maps API</a> on the page.</p></li><li><p>Once included, the script scans the page for the static resource mentioned above. This is done by walking the DOM looking for <code>link</code> or <code>img</code> tags, and checking the value of the <code>href</code>/<code>src</code> attribute to ensure it lies within the same domain as the calling page. The URL of this resource is stored for use later. At this point, if required, the client library can signal to the developer that it is ready for communication with the server. If the resource is not found, the client-library should throw an error and terminate.</p></li><li><p>When a request requires to be made, the client library takes the request parameters and prepares the markup for a form. This form can have any <code>method</code> attribute value, and should have it's <code>action</code> attribute set to the proxy page on your domain. The parameters to be sent to the server should be enumerated as hidden fields within the form. The client library also specifies the resource (in a RESTful sense) that needs to be acted upon. Also, the name of the static resource we had hunted down earlier is passed on to the server. This form is not appended to the document yet. This markup is then wrapped into <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code> tags. The body tag should have <code>onload=”document.forms[0].submit();”</code>.</p></li><li><p>The client library then creates a 0px x 0px iframe, without setting the <code>src</code> attribute, and appends it to the page's DOM. This makes the browser think that the iframe exists in the same domain as the calling page. Then, by using the iframe document object's <code>open()</code>, <code>write()</code> and <code>close()</code> methods the markup created in the previous step is dumped into the iframe. As soon as the close method is called, the form gets submitted to the proxy page on your domain because of the <code>onload</code> in the body tag. Also note that this gives the server access to any cookies it might have created from within it's domain, letting you do things like authentication. In this way one part of the communication is complete, and the data has been sent to the server across domains. However, the iframe's <code>document.domain</code> has now switched to point to your domain. The browser's security model now prevents any script access to most parts of the iframe.</p></li><li><p>The proxy page sitting on your server now queries your REST API – basically doing it's thing – and gets the response. Response in hand, the proxy is now ready to flush the response to the client.</p></li><li><p>If the response is rather large in size, as might be the case with a huge GET call for instance, the proxy breaks it up into chunks of not more than say 1.5k characters<sup><a href="#urlLengthRestriction">3</a></sup>.</p></li><li><p>The proxy is now ready to flush the response. The response consists of iframes – one iframe for each of these 1.5k chunks. The iframe's <code>src</code> attribute is set to the static resource we had discovered earlier. It is for exactly this purpose that we had hunted the resource down and passed on the URL to the server. At the end of each of these URLs, the proxy appends one of the chunks of the response, after a “#” symbol, so that it works as a <a href="http://www.w3.org/Addressing/URL/4_2_Fragments.html">URL fragment identifier</a>. Also, the iframe tags are each given a <code>name</code> attribute, so that the client script can locate them.</p></li><li><p>Meanwhile, the client-side code is where it had left off at the end of step 4 above. The script then starts polling the iframe it created to check for the existance of child iframes. This check of iframes will need to based on the iframe name the server will be sending down. It will look something like this: <code>window.frames[0].frames[“grandChildIframeName”]</code>. Since the static resource we have loaded into the grandchild iframe is of the same domain as the parent page, the parent page now has access to it, even the intermediate iframe is of a different domain.</p></li><li><p>The client script now reads the <code>src</code> attributes of the iframe, isolates the URL fragments (<code>iframe.location.hash</code>), and reassembles the data. This data would typically be some JSON string. This JSON can then be eval'd and passed on to a success handler. This completes the down-stream communication from the server to the client, again across domains.</p></li><li><p>With the entire process complete, the client-library can now perform some cleanup actions, and destroy the child iframe it created. Though leaving the iframe around is not a problem, it is not necessary and simply adds to junk lying around in the DOM. It's best to get rid of it.</p></li></ol><p>This was simply the outline of the process, and there are several additions/improvements that can be done. For example, better control on reading/writing HTTP headers, having a reliable <a href="http://www.devguru.com/technologies/xmldom/quickref/document_readyState.html">readyState</a> value, error handling in case of HTTP errors (4xx, 5xx errors), handling of HTTP timeouts, etc. are all desired. However, this should be enough to get you started.</p><p>If you haven't already realized the significance of this, we should now be able to build much more sophisticated mashups that do much more than the current breed of mashups on the web. It opens up the floodgates to entirely new kind of applications on the Internet – applications we haven't seen as yet.</p><p>Let's enable better mashups! Nothing should now stop you from being able to give open secure access to your site's functionality in JavaScript.</p><hr /><ol style="font-size: 0.9em"><li><a name="moreMethods"></a>A little creative thinking will let you circumvent the problem of browser-restricted HTTP methods when querying your REST API. Send an extra parameter to the proxy page when you are creating the form to specify which method to use. Let the proxy page then hit your REST API with the specified method.</li><li><a name="domainResourceWorkaround"></a>The work around to not having any same-domain static resource would be to ask the API user to have a blank HTML page on his domain, the URL for which should be manually provided by the user to the client script. I don't think this is a great idea since it is an extra step that the API user has to do. However this can be used for one of those if-all-else-fails situations.</li><li><a name="urlLengthRestriction"></a>This 1.5k restriction is to overcome a <a href="http://support.microsoft.com/kb/208427">URL length restriction in Internet Explorer</a>, though most other browsers allow much more. Note, HTTP itself does not impose any restriction on the URL length.</li></ol><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-6394477207194013716?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com14tag:blogger.com,1999:blog-8112154.post-31446602804913177422007-11-09T18:57:00.000+05:302007-11-09T19:13:02.621+05:30Pics from Kerala<p>Finally managed to get some time today to upload my <a href="http://www.flickr.com/photos/rakesh/sets/88409/">pics from my trip to Kerala</a> to Flickr. Here are some of my favorites from that list.</p><br /><p style="text-align:center"><a href="http://www.flickr.com/photos/rakesh/1933152812/" title="Photo Sharing"><img src="http://farm3.static.flickr.com/2089/1933152812_60febec46e_m.jpg" width="240" height="180" alt="Police Orders" /></a><a href="http://www.flickr.com/photos/rakesh/1932339525/" title="Photo Sharing"><img src="http://farm3.static.flickr.com/2326/1932339525_87664ee7ba_m.jpg" width="240" height="180" alt="Attack!" /></a><a href="http://www.flickr.com/photos/rakesh/1933187076/" title="Photo Sharing"><img src="http://farm3.static.flickr.com/2331/1933187076_5ef90f62f3_m.jpg" width="240" height="180" alt="Sunset at the Cape" /></a><a href="http://www.flickr.com/photos/rakesh/1933190826/" title="Photo Sharing"><img src="http://farm3.static.flickr.com/2384/1933190826_5b78bba71e_m.jpg" width="240" height="180" alt="Suchindram Gopuram" /></a></p><br /><p>Head over to Flickr to <a href="http://www.flickr.com/photos/rakesh/sets/88409/">see the complete photo set</a>.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-3144660280491317742?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-26554198994146115642007-10-18T21:30:00.000+05:302007-10-18T21:27:09.533+05:30Dojo, Flash, SWFObject, Packer, IE's "Click here to activate and use this control" and Eval Contexts<p>Boy, that's a long title!</p><p>Solving this problem I had at hand took a good day and a half. What I discovered seems obvious in hindsight, but it wasn't obvious to me until I had solved it. So that no one ever goes through the pain, here's what happened.</p><p>There is this thing I'm working on at work that required the use of <a href="http://blog.deconcept.com/swfobject/" title="SWFObject">SWFObject</a> class simply to get around the IE "Click here to activate and use this control" nuisance when inserting flash files into the page.</p><p>Now, the reason why that message comes up is <a href="http://channel9.msdn.com/ShowPost.aspx?PostID=182027#182027">pretty shitty</a>, but the problem and solution is <a href="http://msdn.microsoft.com/library/default.asp?url=/workshop/author/dhtml/overview/activating_activex.asp">very well documented</a>. SWFObject is supposed to solve this problem. So, rather than re-inventing the proverbial wheel, we decided to use SWFObject. However, needless to say, IE would still keep throwing the message.</p><p>Now, a bit about the setup we have. We are using <a href="http://dojotoolkit.org/">Dojo</a> for this particular thing. I have written a wrapper around SWFObject so that I don't have to bother passing it all the stuff it needs every time I need to use it. Also, on a test machine, we host built versions of the code, which used <a href="http://dean.edwards.name/packer/">Packer</a> to compress the JavaScript. We were using Packer more as a compresser than as an obfuscator, since Packer gave us a considerable improvement in the compression ratios over anything else. On my local machine, I use the unbuilt version of the code.</p><p>Irrespective of where the code ran from, we used to get the nasty message in IE.</p><p>For those who don't know yet, here's how you get around the message - it's pretty simple. Create the object/embed tag from an <em>external</em> JavaScript file, and insert it into the HTML document. It's that simple.</p><p>Now, going by unobtrusive principles, our JavaScript always lies in external files (unless there's <em>very</em> good reason to not do so). So, why was this message showing up? There were two scenarios here:</p><ul><li><p><strong>My dev machine:</strong> Because of the way I had layered the files in Dojo for ease of maintenance, Dojo would dynamically pull in the references on the fly. This is very convenient and makes for easy to organize code. The way Dojo does this is by making an XHR call to the server to fetch the .js file, and then <code>eval</code>ing the code. Now, these evals are run in the context of the window, effectively making them inline scripts. IE thus thought the code was inline, and showed the error message.</p></li><li><p><strong>The test machine:</strong> So, even if it doesn't run on my machine, that's fine if we can get it to run on a test machine correctly. On this test machine we always house the built version of the Dojo file. With a properly written build profile, Dojo might not have to go around and pull in references as required since they would already be baked into the built files. So, that would make the SWFObject code external, and IE shouldn't have a problem with it, right? Almost. Packer requires an eval of the code it has obfuscated to make sense of it. Again, the eval is run in the context of the browser, and IE treats the resultant code as inline, again showing the error.</p></li></ul><p>So, in both the cases, the problem was the context of the eval, though in entirely different scenarios. It could also be concluded that SWFObject cannot ever be compressed using Packer. It was just painful to track down and fix this bug. I hope no one ever has to go through this pain again.</p><p>If you need to know, we had to switch to <a href="http://dojotoolkit.org/docs/shrinksafe">ShrinkSafe</a> to avoid the eval that Packer does. There are definitely better ways to compress, but this should do for now. The code-size increase wasn't too significant, so we were fine with using ShrinkSafe. Ideally, I would use ShrinkSafe for SWFObject and packer for everything else, giving the best of compression and avoiding the implicit eval. This doesn't solve the problem on my local dev machine (since the code is unbuilt), but that doesn't really matter.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-2655419899414611564?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0tag:blogger.com,1999:blog-8112154.post-68997201934617475152007-10-16T11:52:00.000+05:302007-10-16T12:53:35.741+05:30Client-Side Performance Optimization of Ajax Applications<p>There has a lot been said about server-side performance optimization. But a recent report from Yahoo concluded that the server accounted for less than 5% of the time for a user to view a web page. Here's how you can performance optimize the client-side code. Note that this article is targeted towards pretty advanced JavaScript programmers, working with pretty client-heavy applications.</p><h1>Network performance</h1><ul><li><p>This feels just stupid to say: Reduce the amount of source-code you've written. There are several ways of doing this. The first is to simply not write any JavaScript at all. But that might not be an option for you. Another way is to lazy load code - don't download code unnecessarily on the client. This is especially true of single page applications. Another thing you simply must do is pass your code through a good compressor - like <a href="http://alex.dojotoolkit.org/shrinksafe/" title="ShrinkSafe">Dojo's Shrinksafe</a>, <a href="http://www.crockford.com/javascript/jsmin.html" title="Doug Crockford's JSMin">Crockford's JSMin</a>, <a href="http://dean.edwards.name/packer/" title="Dean Edwards' Packer">Edwards' Packer</a> or the <a href="http://www.julienlecomte.net/blog/2007/08/13/introducing-the-yui-compressor/ " title="YUI Compressor">YUI Compressor</a> (or even a combination of those).</p><p>Another thing that I've heard most people recommend is that gzipping of JavaScript files helps reduce network latency. While this is entirely true, <a href="http://support.microsoft.com/kb/871205">a bug in a rather prevelent version of IE</a> makes me wonder if I should do that. If anyone can prove me wrong, I'll only be glad.</p></li><li><p>In all popular browsers today, JavaScript files are always sequentially downloaded. It doesn't matter if HTTP says you can have 2 connections open. It doesn't matter that CDNs on different domains can serve files in parallel. It doesn't matter that Firefox always disregards the HTTP restriction and downloads multiple files all the time. When it comes to JavaScript, all files are always downloaded sequentially.</p><p>This only makes sense, since script should be executed in the order in which they appeared in the markup. Reduce the number of files to be downloaded. This can be done by using a build process, something similar to what the Dojo build system does - combining the JavaScript files into one file.</p></li><li><p>Cache Ajax responses. The network is undoubtedly the weakest link in the chain. Avoid making requests. A request once made should never be made again. Implement cache invalidation if you need. Even then don't fetch data just because the cache is now invalid. Wait till it is actually required. If you never end up needing it, you've saved another hit.</p></li></ul><h1>Perceived performance</h1><ul><li><p>Reduce the amount of source-code you've written. I know this sounds like a repeat of a point above, but I had to bring this up from a perception point of view too. It seems that the more JavaScript that's downloaded, the more time it requires for the browser to interpret it, increasing at an exponential rate (not linear). Which means that even after your code has been downloaded, the browser will just sit there doing (apparently) nothing for some time. Usually, this is a problem above say 500 kb of code.</p></li><li><p>In any case, if you are downloading 500k of JavaScript on the load of the page, there better be a very good reason for it. You should be able to have much faster download times by splitting up these files into <em>modules</em>, which you can download at a later time - maybe on demand.</p></li><li><p>Get something downloaded and displayed as soon as possible. This might be something as simple as markup with the UI skeleton for the application, and simple "Loading..." indicators. It helps a great deal in reducing the frustration in working with an application.</p></li><li><p>If you can help it, put your JavaScript includes at the bottom of the page. This gives the browser enough time to download and render most of the page before even starting to mess with your scripts. Considering that JavaScript downloads sequentially, and doesn't let any other resource be downloaded at that time, you should only download JavaScript once you already have something to show the user.</p></li></ul><h1>JavaScript performance</h1><p>There's a lot that can be said here. I've started getting a lot of kicks lately in trying to milk every millisecond of performance from a browser. So here's what I've learnt so far.</p><ul><li><p>If you are writing a function that returns an array, you usually want to pass in a callback as a parameter of that function. This will improve the performance by <em>at least</em> a 100%.</p><p>Instead of:<code><pre><br /> var anArrayOfData = getAnArrayOfData();<br /> for(var i=0; i&lt;anArrayOfData.length; i++) {<br /> // do something with anArrayOfData[i]<br /> }<br /></pre></code></p><p>Do the following:<code><pre><br /> getAnArrayOfData(function(item) {<br /> // do something with item<br /> });<br /></pre></code></p><p>This is better because you usually loop inside the function anyway to build the array. Having to loop through the returned array again is a waste of processing time.</p><p>Instead of:<code><pre><br /> function getAnArrayOfData() {<br /> var returnData = [];<br /> <br /> for(var i=0; i&lt;largeSetOfData.length; i++) {<br /> // Some code...<br /> if(condition === true) {<br /> returnData.push(largeSetOfData[i]);<br /> }<br /> }<br /> <br /> return returnData;<br /> }<br /></pre></code></p><p>Do:<code><pre><br /> function getAnArrayOfData(callback) {<br /> var returnData = [];<br /> <br /> for(var i=0; i&lt;largeSetOfData.length; i++) {<br /> // Some code...<br /> if(condition === true) {<br /> returnData.push(largeSetOfData[i]);<br /> if(callback) {<br /> callback(largeSetOfData[i]);<br /> }<br /> }<br /> }<br /> <br /> return returnData;<br /> }<br /></pre></code></p><p>This way, the callback parameter is optional, and you still return the returnData, but you could also provide the callback function and avoid another external loop to iterate through the return data. I've changed all the getElementsBySelector methods in my libraries to use this approach, for example. It only seems logical - if I get an array, I will usually need to iterate through it.</p></li><li><p>Use native functionality whenever possible. Case in point: forEach iterators. This is very helpful, and <a href="http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:forEach">part of the 1.6 standard</a>, but the most popular browser in the world can't do forEach loops. Most people either live with it, write their own forEach iterator using simple for statements, or use a library that already has this built in. If you are the second type of person, you aren't achieving much except code readability, which is not a bad thing. Most frameworks' forEach loops also take much the same approach. However, there's a better way.</p><p><code><pre><br /> function myForEach(array, callback) {<br /> if(array.forEach) {<br /> array.forEach(callback);<br /> } else {<br /> for(var i=0; i&lt;array.length; i++) {<br /> callback(array[i]);<br /> }<br /> }<br /> }<br /></pre></code></p><p>In almost all browsers, the block in the if statement will be executed, giving the best possible performance, since you are using native functionality. However in less modern browsers that happen to be more popular and which you have to support but can't do much more about optimization, the else block will still work. Think of it as being the graceful degradation principles of CSS being applied to performance.</p><p>Now, I haven't done it above, but I strongly recommend that you stick to the JavaScript standards when deciding the function signatures of both the <code>myForEach</code> and the <code>callback</code> functions. This is because if the world does become a better place one day, and the most popular browser in the world actually learns how to be modern, you code will work such that it uses the most optimum features in the browser, without you having to change a single line of code.</p></li><li><p>Don't build too much of scaffolding code to make JavaScript behave like classical object oriented programming languages. Usually, you will not end up with much more than helper functions. A lot of the paradigms of classical OO don't apply to JavaScript. Learn to use JavaScript for what it can do. Don't make it what you want it to be.</p></li><li><p>Use threads. Ok, JavaScript doesn't really do threads at all. However, you can kinda simulate the effect of threads. What you achieve by doing this is that you hand over control back to the browser for a brief instant before proceeding with your code. This gives the browser time to react to any other user action that might have happened, make any updates to the DOM that you had asked for, bypass that nasty <q>The script on this page is unresponsive</q> warning, etc. So, how do you do this?</p><p><code><pre><br /> // some code<br /> setTimeout(function() {<br /> // some more code<br /> }, 0);<br /></pre></code></p><p>If you don't understand how exactly this works, this could be a source for a lot of bugs. Use this with caution. However, I've used to get a very high apparent performance very successfully.</p></li><li><p>Cache function results. If for a given set of parameters a function will always return the same results, you really only need to calculate it the first time. Once calculated, save the data in a variable, and read from that variable hence forth. For example:</p><p><code><pre><br /> var squaresCache = {};<br /> function getSquare(number) {<br /> if(!squaresCache[number]) {<br /> squaresCache[number] = number * number;<br /> }<br /> <br /> return squaresCache[number];<br /> }<br /></pre></code></p><p>The example above isn't very good for at least two reasons. Firstly, using this pattern for computing squares is just plain stupid. Secondly, it seems (though it need not be) that <code>squaresCache</code> is a global variable, which is plain evil in any programming language. However, I hope it illustrates the idea of populating the cache the first time the function executes and subsequently reading from the cache instead of re-calculating the data.</p></li><li><p>Strings in JavaScript, like in many other languages are immutable. So, for lots of string concatenation operations, you need to use the string builder pattern in JavaScript too. The simplest way to do that is to declare an array instead of a string, push strings into that array instead of concatenating, and finally call <code>array.join("");</code> to get the concatenated string.</p></li><li><p>Do not use eval. Eval is painfully slow. But why do you need to use eval? Other than converting a JSON string to an object, I never write any code that needs to be eval'ed. Remember the other cousins of eval - <code>new Function(someString)</code> and <code>setTimeout(someString, ms)</code>. You don't need the Function constructor at all, and you don't need to pass strings into setTimeout at all. Instead, in both cases, you can use anonymous functions. Thus, the implicit eval is avoided. Using anonymous functions give the added benefit of retaining variable scope through the creation of the closure. The eval is always carried out in the global scope.</li><li><p><q>Unfold</q> your if statements. This is particularly useful for code that checks for browser features. For example, instead of:</p><p><code><pre><br /> function addEvent(element, eventName, callback) {<br /> if(element.addEventListner) {<br /> // add the event one way<br /> } else {<br /> // add the event another way<br /> }<br /> }<br /></pre></code></p><p>Do the following:<code><pre><br /> if(element.addEventListner) {<br /> function(element, eventName, callback) {<br /> // add the event one way<br /> }<br /> } else {<br /> function(element, eventName, callback) {<br /> // add the event another way<br /> }<br /> }<br /></pre></code></p><p>This unfolding of ifs applies even to loops, for example. So, if you can keep if statements outside a loop, do that. It doesn't make for readable code, but it's significantly faster. Bonus points to you if you just thought to yourself that my forEach example can be improved using this technique.</li></ul><h1>DOM Performance</h1><p>Of all the parts making up client script, DOM manipulations are the slowest. So, you have to take the most care here.</p><ul><li><p>Use innerHTML. Don't be too much of a purist. Being a purist won't make your application faster. You wouldn't believe how much faster your code is if you use innerHTML.</p></li><li><p>Never update the DOM. Ok, if that's not possible, at least do it as infrequently as possible. Bunch up your updates to the DOM and save them for a later time. Realize that it is not the size of the update but the high frequency of updates that's slow. Doing <code>appendChild</code> in a loop is updating the DOM frequently. Caching the markup in a string, and then setting the <code>innerHTML</code> in the end is batching and updating infrequently. The second is much faster.</p></li><li><p>However, the technique above is mostly only useful if you are adding new stuff to the DOM. What if you are updating existing elements on the DOM? How do you keep updates to a minimum when you want to change style, class names, content and children of a node that already exists? Simple. Clone the node you want to work with. Now you will be working with a clone of the real node, and the cloned node doesn't exist in the DOM. Updating the cloned node doesn't affect the DOM. When you are done with your manipulations, replace the original node with the cloned node. However, note that the performance problems here are because of the content and rendering reflow that the browser has to do. You might get similar benefits by simply hiding the element first, making the changes, and then showing it. Though I haven't tried this, it should work in theory.</p></li><li><p>Keep track of events. For me, this is the worst part of working with the DOM. This is important because when your application (or any DOM nodes) are being unloaded or destroyed, you will have to manually unregister the events from the nodes BEFORE you destroy the elements. Yes, this is the garbage collector's job, and that's supposed to be the job of the environment your code runs in, but guess which browser is the offender here. Internet Explorer doesn't free all the references <em>even when the user leaves your web page</em>. Unless you want your web app to earn the reputation of being responsible for many a crashed browser, and a horrid browsing experience for <em>other</em> websites too, count your references.</p></li><li><p>If you are going to iterate through a node list to attach event handlers, you are probably wasting processor time. Instead, simply attach the event handler to some parent of the node list and read from the event object to know what was clicked on. You save the cycles required to iterate over the nodes this way.</p></li><li><p>Avoid calls to functions like getElementsBySelector, where there's lot of DOM walking involved. If you cannot, then make sure you work on as small an area of the DOM as possible. If your favourite version of getElementsBySelector lets you send in a root node under which to search, do that. Otherwise, provide a very high specificity, starting with a "#someId" so that the function can narrow down the search. Also, understand how these functions work internally. For example, you could use a getElementsByClassName to find divs with the class "foo", and the implementation of getElementsByClassName will probably be just three lines, However, using getElementsBySelector("div.foo") will be faster in almost all frameworks, even though it might have a hundred lines of code in it's implementation, since it has less DOM walking to do.</p></li></ul><p>Sorry for the kinda horrible organization of this post. I should also say that not all of these ideas are my original - I found a lot of these by reading many sites scattered across the web. However, I hope you found this post useful.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-6899720193461747515?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com3tag:blogger.com,1999:blog-8112154.post-89564938848985454772007-09-21T10:55:00.000+05:302007-09-21T11:24:42.103+05:30Much Deserved Update<p>It's been an eternity since I wrote to this blog, so an update is in order. I fear this update will seem very similar to <a href="http://piecesofrakesh.blogspot.com/2005/12/back-in-action.html" title="Back In Action">a pervious post</a>. Also, please bear with me if this post seems too long.</p><br /><ul><li><p>Much in the vein of that previous post, I've quit my job again. <a href="http://www.iventa.com/" title="Iventa Corporation">Iventa</a> was a great place to work at (Notice, I didn't say that about my employer before Iventa), and it has let me learn, explore and part with (and thus expand) my knowledge more than any other place I've worked at before.</p></li><li><p>I'm now with <a href="http://www.cleartrip.com/" title="Cleartrip.com">Cleartrip.com</a>. One of the top travel portals today in India, Cleartrip could easily be mistaken to be <q>just a travel thing out there</q>. Truth is, outside of the <a href="http://www.iitb.ac.in/" title="IIT Bombay"><abbr title="Indian Institute of Technology">IITs</abbr></a> - an organization I used to interact with regularly - this is one place where I've seen more innovations happen more frequently than any other place. All the people you meet at Cleartrip are gurus in their areas of work. I can only consider myself to be lucky to be in the company of such a congregation of sheer genius.</p></li><li><p>I've joined Cleartrip as a JavaScript developer guy. If you look at that from a organizational chart perspective, this is a slight demotion in rank for me. But that was completely intentional. I was starting to move towards managing people at Iventa, and I think I had still not had enough of playing with technology. I guess that only means that I want to grow some more in the area of technology, and not in the area of management. Tech is where I get my kicks from, and I don't see that changing at least for some time.</p></li><li><p>The management at Cleartrip was kind enough to allow me a short vacation between jobs. I took the opportunity to go to Kerala - this time not because it's my home town, but because I had never been to a place of such scenic beauty as a tourist. I've got very interesting stories (including one where I'm chased by a wild elephant trying to protect her kid from me, since I was armed with a camera), but I've got even more interesting photographs. I shall be uploading them soon. Which brings me on nicely to the next two points.</p></li><li><p>The reason I've not uploaded any pics so far is because my beloved Hangy is dead. Again. This time, it seems that the moisture from the Mumbai rains got to her chipset on the motherboard, and AFAIK there's no one who can fix that. So, my only option is to replace the board, but I'm reconsidering that in favor of a huge upgrade. I've meanwhile asked my computer-fixit-guy to come up with an alternative - probably a second-hand motherboard I can buy from him. Let's see what he comes up with.</p></li><li><p>So, assuming I get ready to post pics online to share, which service is really the better? I like Google, so Picassa seems to be an interesting option, but I've not found that to be reason enough to change from Flickr yet. Any opinions for or against either of these? Please enlighten me.</p></li></ul><br /><p>This post would be incomplete without some more important information.</p><ul><li><p>This blog is NOT dead. I really mean to post much more. In fact, since Hangy's dead, I got my MacBook Pro from work home today so that I can compose this post. (Which incidentally makes this the first post on this blog written on a Mac. I wouldn't be surprised if the next one is written in Emacs on Ubuntu, or something!)</p></li><li><p>That said, this blog is going to deviate a bit in its direction. So far this blog has largely been about markup and style. However, <abbr title="In my humble opinion">IMHO</abbr>, all that had to be said about markup and style has been said, either here or elsewhere. The subject is so beaten now, that a new acronym had to be invented in hopes of reviving interest. (<a href="http://microformats.org/wiki/posh" title="Plain old semantic HTML"><abbr title="Plain Old Semantic HTML">POSH</abbr></a>, for God's sake!) Meanwhile, I've decided to move on. I need to give a better explanation of why I'm moving on, and I think that's a topic for another post. I really want to share my thoughts about why I think all the fuss about markup and style is not worth it - at least in the connotations it started to carry. That would be an ironic post, since <a href="http://piecesofrakesh.blogspot.com/2004/09/economics-of-xhtml.html" title="The Economics of XHTML">the most popular post on my blog so far</a> has vehemently promoted XHTML! I guess I had to go through all of it to learn how unimportant it is.</p></li><li><p>I've moved on to JavaScript, if you haven't guessed already from my last few posts. I've been hungrily learning so much about JavaScript these days, that I can easily claim to know much more than some of the good JS coders out there. I know that's a tall claim, but on more than one occasion I've realized that some of these gurus' arguments don't make sense. I guess that's a good sign.</p></li><li><p>Which nicely brings me on to the last point I want to share. This blog is going to turn from a primarily web standards promotion blog to a primarily JavaScript hacking blog. I shall now discuss lessons I've learned in JavaScript, application architectures from a JavaScript thick-client perspective, interesting hacks and tricks in JavaScript that I've picked up along the way, and occasionally the stupid browser nuances (you know which browser I'm talking about) I come across. Expect posts talking about JavaScript as a language (one of the most modern - old as it is - and among the richest most expressive languages in the entire computer industry IMHO, and already available on your desktop!) for all the cool things it can do, and JavaScript from a more serious application design point of view, being an important part of application architecture design sitting at the top-most layer, ensuring that users have a great experience. This particular topic about JavaScript being a serious thick-client programming language has been of particular interest to me lately, and the few forays I've had are very promising. So, expect me to talk a lot about these kinds of topics now on.</p></li></ul><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-8956493884898545477?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com4tag:blogger.com,1999:blog-8112154.post-20028799124979785882007-06-18T16:48:00.000+05:302007-06-20T00:28:11.520+05:30URI fragment identifiers and HTTPI came across an interesting problem today with how <abbr title="HyperText Transfer Protocol">HTTP</abbr> handles <abbr title="Uniform Resource Identifiers">URI</abbr> fragment identifiers. Here's the spoiler - it does not!<br /><br />Here's the long story. If you are on a page which has a URL that looks like this:<br />http://www.domain.com/page.html#fragment<br /><br />Now, #fragment is known as the URI fragment identifier. This particular thing has got very popular lately with it's potential uses in Ajax applications, since it can be easily (mis)used to let client-side code perform many actions.<br /><br />This also helps take care of some back-button problems with Ajax. For example, let's say you are on page.html. Then, you perform some client-side operation that appends #fragment to the URL. Now, let's say you navigate to page2.html and press the back button, you would land up on page.html#fragment. Then, the JavaScript on the page could read the #fragment and perform an Ajax action to restore the page to the state you had left it at.<br /><br />However, I just discovered when working on this one project that the #fragment is never sent to the server as part of the request headers. The HTTP specification says nothing about handling URI fragment identifiers, and sure enough most browsers do nothing with them.<br /><br />So, if you ever have to read the #fragment on a server, remember that you can't! That's just one more of the problems that we have to deal with as <abbr title="Rich Internet Application">RIA</abbr> developers.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-2002879912497978588?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com3tag:blogger.com,1999:blog-8112154.post-74386028936415730072007-06-12T20:59:00.000+05:302007-06-12T21:04:27.802+05:30Safari for WindowsYes, that's right. It has finally happened. <a href="http://www.apple.com/safari/" title="Safari for Windows">Safari for Windows</a> is now available as a free download.<br /><br />There are still some questions unanswered - my number one question is if it uses the same rendering engine as the Mac version. I hope it does.<br /><br />On a side note, I wonder what will happen to <a href="http://try.swift.ws/">Swift</a>.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8112154-7438602893641573007?l=piecesofrakesh.blogspot.com'/></div>Rakesh Paihttp://www.blogger.com/profile/00328152982823663876noreply@blogger.com0