Duff's Device for JavaScript

Nicholas Zakas in his book "High Performance JavaScript" has mentioned about Jeff Greenberg's JavaScript implementation of Tom Duff's original technique of unrolling loop bodies in order to let each iteration perform job of many iterations.

for (var i = 0, loopLen = items.length; i < loopLen; i++) {
    process(items[i]);
}

can be rewritten with this technique as:

var arrLen = items.length;
var loopLen = Math.floor(arrLen / 8),
    startAt = arrLen % 8,
    i = 0;

do {
    switch (startAt) {
        case 0: process(items[i++]);
        case 7: process(items[i++]);
        case 6: process(items[i++]);
        case 5: process(items[i++]);
        case 4: process(items[i++]);
        case 3: process(items[i++]);
        case 2: process(items[i++]);
        case 1: process(items[i++]);
    }

    startAt = 0;
} while (--loopLen)

Suppose, the "items" array contains 10 items. The first iteration will call "process()" 2 times - 'case 2:' and 'case 1:'. (Note that the break statement has been excluded intentionally). The second iteration will invoke "process()" 8 times. This has reduced the number of iterations from 10 to just 2.

Jeff Greenberg has even improved this pattern further by having a separate loop construct for the first part of the iterations and totally getting rid of the 'switch' statement thereon.
var arrLen = items.length;
var i = arrLen % 8;

while (i) {
    process(items[i--]);
}

i = Math.floor(arrLen / 8);

while (i) {
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
}

Though for smaller number of iterations there isn't a significant gain on performance, it is seen that, at 500,000 iterations the execution time is up to 70% less than a regular loop.

Performance comparison between ways to declare a function in JavaScript

Results on Chrome

  1. var start=(new Date()).getTime();
    for(var i=0;i<1000000;i++){
        function fn1(){
            return "Traditional approach";
        }
    }
    var end=(new Date()).getTime();
    console.log(end-start);

    Test 1: 946 milliseconds. Test 2: 950 milliseconds.

  2. var start=(new Date()).getTime();
    for(var i=0;i<1000000;i++){
        var fn2 = function(){
            return "Using var keyword";
        }
    }
    var end=(new Date()).getTime();
    console.log(end-start);

    Test 1: 1476 milliseconds. Test 2: 1476 milliseconds.

  3. var start=(new Date()).getTime();
    for(var i=0;i<1000000;i++){
        window.fn3 = function(){
            return "As a member of window object";
        }
    }
    var end=(new Date()).getTime();
    console.log(end-start);

    Test 1: 1809 milliseconds. Test 2: 1808 milliseconds.

30 best practices to boost your web application performance

  1. Limit interaction with DOM as much as possible. Store DOM references in local JavaScript variables before using them if you need them more than once. Consider setting innerHTML over document.createElement/appendChild().
  2. eval() is evil. So is the constructor new Fuction(). Avoid them to the maximum extent.
  3. Say no to with statement. It introduces an extra scope to search each time variable is referenced and the contents of that scope is not known at compile time.
  4. Consider for() over for-in loop. The for-in loop requires the script engine to build a list of all the enumerable properties and check for duplicates prior the start.
  5. Instead of putting try-catch inside a loop, put the loop inside a try-catch. Exception handling should be done at as high level in the script where it does not occur frequently.
  6. Even the holy Bible mentions this - NO Globals. Variable in the global scope persist though the life time of the script, whereas in local scope they are destroyed when the local scope is lost. Also when a global variable is referenced inside a function or another scope, the script engine has to search through the whole scope to find it.
  7. fullName += 'John'; fullName += 'Holdings'; is faster than fullName += 'John' + 'Holdings';
  8. But if you have multiple string concatenations, prefer pushing to an Array and then calling the join() method on it. This is particularly helpful while building HTML snippets.
  9. For simple tasks, prefer Primitive operations over function calls e.g. val1 < val2 ? val1 : val2; is faster than Math.min(val1, val2); and similarly myArr.push(newEle); is slower than myArr[myArr.length] = newEle;
  10. A function reference perform better than (hard coded) string literals as parameters to setTimeout() and setInterval(). E.g. setTimeout("someFunc()", 1000) will perform slower than setTimeout(someFunc, 1000)
  11. Avoid DOM modifications while traversing. The DOM element lists returned by functions like getElementsByTagName() are live; so changing these collections won't wait for execution to finish first. This might also cause an infinite loop to occur.
  12. Store references to object members (properties and even methods) if you are going to need it more than once e.g. var getTags = document.getElementsByTagName; getTags('div');
  13. Store local references to out-of-scope variables to provide quicker access and avoid lookup. E.g.
        var a = 'something';
     
        function foo() {
            //create a local reference for 'a', which is out-of-scope of this function
            var l = a;
            
            //do something with l
        }
  14. for(var i=0; i < someArray.length; i++) {...} is slower than for (var i=0, loopLen=someArray.length; i<loopLen; i++) {...}.
  15. Add Expires and max-age directive of Cache-Control HTTP Header in server responses.
  16. Optimize CSS. Prefer <link> over @import. Refer to this beautiful presentation http://www.slideshare.net/stubbornella/object-oriented-css
  17. Use CSS sprites to cut down on image resources
  18. GZip .js and .css files. On Apache if you set something like this in .htaccess, it will also gzip your HTML, XML and JSON
    AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/x-javascript application/json
  19. Use JavaScript minifier. Apart from YUI and JSMin, also try Google Closure http://closure-compiler.appspot.com/home (Courtesy: James Westgate, a fellow reader)
  20. Optimize each and total number of resources for every view and split them across sub-domains to enable parallel downloads. For more information on parallel downloads, read this http://yuiblog.com/blog/2007/04/11/performance-research-part-4/
  21. Put stylesheets at the top to help progressive rendering on many browsers including IE
  22. Try to keep your DOM structure as light as possible. The size of DOM slows down all the operations related to it such as reflowing, traversal and DOM manipulation. document.getElementsByTagName('*').length should return as small value as possible.
  23. Pay attention to the selectors you use. E.g. if you are trying to collect the list items which are direct children of an unordered list, use jQuery("ul > li") rather than jQuery("ul li")
  24. While toggling element visibility (display) remember this: element.css({display:none}) is faster than element.hide() or element.addClass('myHiddenClass'). But unless you are using it inside a loop, I vote for element.addClass('myHiddenClass') because it keeps your HTML clean - remember that thumb rule from my earlier article? No inline CSS or JavaScript.
  25. When you are done with variable references to DOM, nullify them. JavaScript leaves that power with you.
  26. With AJAX, GET works faster than POST. So prefer GET wherever you can. Just keep in mind IE restricts the GET request length to 2K.
  27. Go easy on scripted animations. Animation without hardware support is slow. Try to avoid excessive use of animations which do not bring any real usability value.
  28. Avoid background-repeat if the background-image is small relative to its containing element. Interaction such as scrolling is extremely slow if background-repeat property is set to repeat-x or repeat-y combined with a background-image of a size which needs to be repeated multiple times to fill in the element's background. Try a commonly used CSS pattern to have a big enough background-image with background-repeat: no-repeat.
  29. Do not use <table>s for layout. <table>s often require multiple passes before the layout is completely established because they are one of the rare cases where elements can affect the display of other elements that came before them on the DOM. And for data tables, use table-layout:fixed; this will allow a more efficient layout algorithm and let the table render row by row according to the CSS 2.1 specification.
  30. Always fall back to core JavaScript whenever possible. Limit framework usage.

Tips: Building Wireframes for Web UI

The nature of UI development is so complex that fitting it into a set of rules is simply not possible. The only way to become a pro in this field is only through constant practice and efforts to better the results by learning more out of small mistakes.

When one is working on a wireframing (also called as 'interactive mockups') assignment, the very first difficult thing is to plan your bits and pieces across HTML and CSS. Things keep changing all the time; so whatever you do, must be flexible enough. This is not possible most of the time and that shouldn't de-motivate you from delivering quality. Do not hesitate to go back to completed wireframes as many times as required and revise them. You will face a lot of reluctance from the developers in this process, but just keep one thing in mind - the only thing that matters at the end is the quality; no one will ever bother to listen to your excuses. So, don't worry about the re-work trouble you are creating for others; this has to be done.

I usually try to follow these tips (I expect readers of this article to be familiar with building HTML wireframes. So forgive me for not providing detailed explanation on each tip. Also, please note, this is what I believe and follow; it may or may not suit everyone out there; so please be kind enough to ignore what doesn't seem right for you)

  • Request for as many screen mockups (PSD or whatever your designers use) as possible before starting. Talk to your manager/client/team lead/visualizer to get as much idea about the application as possible and thereby, understand the expected user experience flow before-hand. Ask for sketches or anything that will give you a rough idea about the rest of the screens in the application.
  • Once you have the base ready to start your work, put everything together at one place (I usually keep it under a folder called 'source') so that you can refer to all of them at any point you wish. Believe me you will be hitting this place more often than anything else.
  • Before starting, go through all screens, preferably arranged in user experience flow order, as many times as you can; slowly. Identify the repetitive elements and plan immediately how you are going to structure them.
  • Now think whether you can employ a common layout template. First, plan everything (HTML, CSS, JavaScript) in your mind. Remember that age-old saying, "Everything happens twice. Even God created this Universe twice; first, in mind and then in real."
  • Structure your files properly. I usually follow this basic template:

    <application-root>
    |----    index.html
    |----    {other html files}
    |----    <stylesheets>
             |----    common.css
             |----    home.css (and so on)
    |----    <javascripts>
             |----    common.js
             |----    messages.js (internationalization/localization) - never use hard-coded strings in your JS code
             |----    home.js (and so on)
    |----    <images>

  • I use HTML5 doctype and I recommend that to everyone. Don't worry, all browsers support it. Yes, IE6, too!! So, the top of every HTML file I code, looks like this

    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
            <title>....

  • Keep validating your HTML before every 'file close' action on your HTML document. I use gedit and rely on http://validator.w3.org/#validate_by_input - which works pretty well for me.
  • Try to make your HTML structure support SEO well, even if your application specs didn't mention about it.
  • Keep your HTML clean - absolutely NO CSS or JavaScript
  • Use <table>s. What??? Yes, not for layouts, but wherever there is tabular data in the content, use tables.
  • Make sure every 'clickable' text uses anchor. Don't just hook-up JavaScript handler to a span, div or an li element. (Talk to someone from QA if you are in doubt over this :P)
  • For CSS, stick to the thumb rule - no inline styles. Not even the jQuery $(".blah").show() or hide(). Define an application level CSS class .hiddenEle {display: none;} and toggle (add/remove) the class through JavaScript.
  • The CSS class names should be brief; but don't mind using a narrative name rather than something absurd. You can always gzip your resources later.
  • Avoid defining a CSS class by an element id as much as possible; unless you are very sure that there is absolutely no scope for the style definition to be reused anywhere else in the application. e.g. #myElement {...}.
  • Never declare a CSS class by HTML tag name. e.g. body {...}. (A brief discussion with a colleague about it - http://www.webuiarchitect.com/never-declare-a-tag-level-css-class-0 )
  • If you see any inconsistency in the design elements across the screens given to you; please don't be shy to point it out. Nobody is perfect. And your suggestion is to improve the user experience, so fight for it, if you need to. This is going to make your work more interesting and add substantial value to what you do. So don't sit there like a clerk.
  • It is quite possible that you identify a common pattern a bit late in the design process. Pull it out immediately in common.css. Revise the already delivered HTML pages. Talk to developers and make sure they take care of the changes at their end. Every time, you go back to them and ask for making changes, do not expect a warm welcome. Try to explain to them why the change is important. Those thoughts will be even more clear in your mind when you talk about it to others; making it sound in your own knowledge-base.
  • Ok, now on how to handle the God itself - JavaScript. I never had a doubt that JavaScript is the most powerful programming language, the machine race has ever seen. And with great power, comes even greater responsibility. Avoid using third-party ready-made widgets/plug-ins as much as possible. The whole developer world thinks they do a smart job by just utilizing the code already written by somebody else. Please try to understand, on a Web UI, even a slightest requirement difference can make the third-party plug-in either completely useless or a huge overhead. So adopt wisely, if you have to, at all. I would advice to stay away from it, unless what you need is a very complex component like a editable grid. Code everything yourself! Of course, use jQuery for the base. When it comes to Web UI development, believe me, it is totally different from any kind of development - all rules fail. What ultimately counts is experience - mainly from failures. So take my word - kill your urge to make use of pretty looking and so called smart-choice JavaScript plug-ins - they will make your life difficult later on. I just completed an assignment and like always, only used core JavaScript with some help from jQuery to add all event listener place-holders. Tabs, modal dialog, complex form elements and all; I did it on my own. It wasn't more than 4-5 lines of code each, anyway.
  • Use CSS rounded corners and shadows unless it comes to branding. Avoid images for buttons and section headers. If needed you can use background image; but big 'no' to text embedded in an image. Convince your manager/client on the performance benefits and inform about the small compromise. And let them take a call on it.
  • CSS sprites a must!!!
  • Double verify the image optimization your designers have done. Damn, you are fighting day and night for every KB that gets in through your code, and you don't want it getting nullified by improperly optimized images.
  • Please! please!! please!!! format your code (HTML, CSS and JavaScript) thoroughly. For indentation, I use 4 spaces as 1 tab; I have seen it a common practice.
  • Comment anywhere and everywhere - HTML, CSS, JavaScript. Don't think about file size here. Put comments on new line - especially HTML. Back-end developers normally use tools like Eclipse or Aptana where they could collapse/expand tags/code blocks. Having comments on separate lines will help in this case. The comments are anyway going out after compression process. What's more important here is making your developers' life easy; and they will love you for this.
  • Throughout the process keep talking to the designers - to learn about forthcoming changes; and to developers - to cross-check their comfort in adapting to your front-end. Take suggestions from both of them and implement wherever possible.
  • If you find any usability concern, raise your hand immediately. Remember, you are the first user.
  • Being socially active and aware helps in every aspect of life, but in UI development, it could be life saving. Hook yourself on Twitter and other social platforms and be in touch with professionals in this field. This thing keeps you running on your toes forever.
  • If you haven't already, then learn what HTML5 offers in totality. I loved everything it introduced; especially, the 'data-' attributes. HTML5 talks pure common-sense. (I am in the process of completing my article "HTML5: A-to-Z in brief" and will shortly post it here).
  • Keep all browsers from the specs matrix open while you work on each of the views. And test well before you deliver; especially before you deliver. It leaves a bad after-taste if someone finds out a small problem in your submission. So add those 2 extra, but crucial minutes to each cycle and have a good-night sleep.
  • Once the whole assignment is delivered, your job is done! You lazy bum, get up!!! It has just started. Now, how useful all your hard work will be, if one of the back-end person misses a closing tag!! Validate the end markup from the browser (served by the actual server) and even the AJAX updates (forgive me, I simply decline to write it as 'Ajax'). Also, make sure they are all aware of the resource distribution and compression techniques to score high on bandwidth.
  • When you take up the next wireframe assignment and learn something new which could also help in the previous project, have a casual talk about your findings with the respective manager/client. Believe me once again, they will appreciate it.

Lazy loading of images across different browsers

A colleague pinged me today over an IE6 issue where she saw background images on elements with style 'display:none' are getting loaded on IE6 on page load but not on Firefox.

My first take was, this shouldn't be an issue at all. I mean, browser developers should have this freedom to decide whether they want to load these images upfront or on-demand. As an UI developer, if I want to have lazy loading on particular elements, especially images, I should handle that explicitly.

I could check with Chrome and found that it also loads those 'display:none' images upfront. So, absolutely nothing wrong there.

For Dummies - Difference between Standards and Quirks mode

In "Standards" mode browser tries to render the web page content by following HTML and CSS specifications; while in "Quirks" mode, it tries to duplicate its own older version (backward compatibility mode).

The simplest way to switch the browser between the two modes is by toggling the existence of a valid DOCTYPE declaration.

Please note: For putting all versions of IE into "Standards" mode, the DOCTYPE declaration must start on line 1 char 1. Even a single whitespace character preceding this declaration puts all IEs into "Quirks" mode.

There also exists a third compatibility mode called "Almost Standards" which adheres to CSS2 specs for vertical sizing of table cells. This mode exactly behaves like "Standards" except the layout of 'images inside table cells' follows "Quirks" mode.

You can verify the current compatibility mode by just checking the DOM extension document.compatMode.

This returns "CSS1Compat" for "Standards" and "Almost Standards" modes; while for "Quirks" mode, it returns "BackCompat".

Try this from your browser's address bar: javascript:alert(document.compatMode);

What is so great about Posterous?

  • Post from anywhere:
    • Post through E-mail: Consider, I'm explaining a possible approach on a task to my sub-ordinate or justifying a reason behind an architectural decision to my manager. This stuff can be very generic. I can convert this into a blog with no extra effort by just adding post@posterous.com into the recipients' list.
    • Post From a Browser: This is really effective. A blog need not necessarily be an original thought; it can be based on an article or a picture that I would come across anytime anywhere. Just select the content from browser and click on the Posterous Bookmark, add your comments and done! This way the frequency of posts goes up naturally. The blogs need not be huge write-ups; but even few random lines.
  • Lightening fast sharing. I can either send my posts to twitter@posterous.com or twitter+facebook@posterous.com and immediately a link to the post is published on my social networks. Genius!
  • Amazingly simple and direct User Experience. I never felt like searching for something; everything was placed at the right spot.
  • Two way information channel. Reading and searching for topics of your interest is equally easy. And not only that you can build your own knowledge hub by subscribing to authors of your interest.
  • Feature rich. This is an element of surprise for most of the users. When things are very simple, quick and effective, it is obvious to expect some lightness towards features. Rich text editing, HTML support, variety of themes to select from, Tagging, RSS, Auto-posting to social networks, Google Analytics, Privacy settings - everything you want in your blogging website, Posterous has it!