Thursday, August 28, 2008

Optimize your javascript for enterprise v1.2

Updated 9.10.08 to 1.2. Items added/modified for 1.2 are in blue.

The following are optimizations you can use for any browser when writing client-side code... most especially for Internet Explorer (ahem), and most especially when you are focused on enterprise installs. First, read a few paragraphs on where I am coming from.

This blog will be continually updated, instead of me just making new blogs. You'll know it is updated, because I will attach a version number every time I change it.

These will help speed up the performance of your code if you are dealing with large amounts of data that you need to store in memory over long periods of time. You may see this more nowadays as you use your wonderful Ajax parsing code to keep users on the same page or view.

Unless you are using perhaps the nicest browsers ever to be created (imo), Safari, then I suggest you stick to the lowest common denominator... and what is that? It's Internet Explorer 7. Up until this year, it was IE6, with all of its shortcomings. At an ancient and withering age of 7 years old, IE6 is the official lowest of the low and the dumbest of the dumb.

Many heavy hitters that purchase enterprise software are slow to upgrade. And since IE is a standard install on Windows machines - it means - you guessed it, guys like me have to code for older browsers. With web, it's IE7. With enterprise, your lowest common denominator is ie6. (more on why this is true and a more comprehensive list of differences between web and enterprise in a future blog).

The most salient point I can make about coding for enterprise versus web is that at the end of the day, your customers absolutely must have working code - and code that works fast, is reliable and consistent. An engineering disaster-miracle like will not cut it in the enterprise world. Often there are not millions of users hitting your system, so you have no excuse and customers know this. To that end, it is your job to find the path that gets the job done - which is not always the cleanest or best path.

Internet purists are going to scoff at me, but I am truly a standards guy. I am a purist and a perfectionist. But I am also an enterprise guy - not a web guy (although my colleague Matt is helping me turn a new leaf in this area) - so I have to do what I can to manage extremely large amounts of information on top of a leviathanic, sprawling multi-tiered enterprise framework with multiple millions of lines of code and literally billions of dollars at stake.

The analogy I use for the enterprise thin client interface is that of the Hoover dam. Have a look. That relatively tiny and thin wall is all that stands between godly oceans of information and your users. Do it right and the dam acts as a usability filter - only what is required gets through. Do it wrong... and you're soaked. Memory leaks. Browser CPU hangs. Usability issues over SSL connections and RDP. Anyone in my position understands these problems.

So, to repeat, here are optimizations that are always good, that in some cases are browser-specific, and work wonders for long-standing interfaces that must avoid memory leaks. Most of this is through my experience, but I will try to site references where I can.

1. Don't put classes directly on your HTML elements during an iteration, where said iteration is more than 25-50 items.
  • If you must use classes in order to satisfy a requirement for getElementsByClassName(), then always programmatically capture and then assign classes after the document is loaded.
  • It's IE that suffers the most from this. And as you will find, it's IE, even IE7 that suffers the most from everything you try to do intuitively. Firefox adheres to standards and deals with DOM in a way that fosters intuitive programming. IE adheres to standards and deals with DOM in a way that fosters kludges.
  • See this performance analysis I did on version 1.0 of a select box factory I am working on. Bottom line, is that it shows other browsers do better when classes are set inline, and IE does worse, but moreso than other browsers do better. Your call. Results of performance testing
2. Avoid using a table element for large matrixes, or page it if you can't.
  • Unless you have lazy loading implemented, browsers like IE will not show the table until the contents of table are loaded. This means perceptual slowness.
  • Can you get CSS to work instead? Go for it. But if you must have a table, then implement server-side or client-side paging. The assumption here is that you have so much data that you can't show it all at once. Page it.
  • In all other cases: tables are fine! Yes! I give you freedom to use tables, and get out of the world of CSS for a minute. Tables are great things - and they allow you to add a structure to a page in no time flat - without having to hack away at CSS styles for hours on end. For Enterprise, and for the more moderate amounts of data, tables are the way to go.

3. Avoid memory leaks and circular references

  • These can creep up on you, especially in IE. The best tool to use that I have found is ProcessExplorer. It tells you how much memory has been allocated by the process locally, as opposed to how much memory the process is currently using. Memory leaks are obvious once the program in question (IE) never releases memory and in fact, grows it over time. This can not only kill your process, but in some cases can hang your computer.
  • Assigning objects to references may cause circular references in IE. Try sending on the id of the object, then manipulating the item directly. Circular references can cause memory leaks or, if you are using mooTools v.1, they may cause the mooTools GarbageCollection to take longer than the browser timeout for unload(). This will make the browser alert the user that a "script is running slowly" when in fact mooTools has just not cleared the memory yet.
  • Opacity manipulation through javascript will cause memory leaks in IE.
3. Do / Don't do this in mooTools v.1.1 (and possibly in v.2).
  • Just like classNames, don't programmatically make new Elements() over iterated items because this takes up way too much memory per item. Your browser will complain when you to try unload().
  • Morphing works poorly in ie6 with mooTools v.1.1 Many styles are not supported. mooTools has fixed much of this in v1.2
  • mooTools v1.1 and ie6 is a terrible combination to deal with regarding CSS. Bottom line: you are going to hate life if you have to deal with this. The number one reason is that you can't use selectors effectively during morphs or style changes in mooTools in ie6 - so your going to have a huge CSS file with many duplicate classes to support transitions.
  • Can't seem to get the keyUp, keyDown or keyPress events to fire in Firefox when you add them to a div? Well, take that div and set the tab index to -1. div.setAttribute("tabIndex","-1"). This fixes what I think is a bug in attaching events for gecko. Source (may not be a valid link)
  • converting from mooTools 1.1 to mooTools 1.2? Oops! Don't use the document.firstChild as your droppables target, for drag and drop elements. Will cause cpu hang 100%. This was not an issue in version 1.11.
  • When converting from mooTools 1.1 to 1.2, watch for these very common transitions.
  1. is now Browser.Engine.Trident, and many more located (here)
  2. is no longer used. try Fx.Tween.
  3. Many more to come. These were just the easiest ones to spot.

  • Still finding your cpu pegged at 100% in IE when performing a click event in mooTools but can't for the life of you find the reason? There are two ways to solve this issue:
  1. You are probably swapping innerHTML right? Or modifying it? Be careful. There is a bug in IE where you must initialize the html with a string first, then attach your html.prepended to the innerHTML you want to add. You may also lose all your events that have been added. This will cause you a major headache! To solve, place any string in quotes += " ". Be sure not to use an empty string - but anything else should work.
  2. Or, Take the focus() off the page by placing the focus() on another element. This short-circuits the process and stops the CPU from pegging out.

4. Avoid these common mistakes
  • Use THEAD if you are injecting a table into the DOM. If you don't then IE won't show it.
  • Don't rely heavily on margins. of all the CSS styles in the universe that are browser-compatible, margins have the most variation. If you use margins too heavily, then you are subject to a wide range of kludges for different browsers and different DTD declarations. Regardless, you're safer off with padding if you can use that as your styling mechanism for spacing.
  • When assigning highlight effects with mouseover and mouseout, or mouseenter and mouseleave, don't try to change the background color of two elements at once. For example, if you have a table row with a button inside the table cell - and you want the button to change also when you highlight the row - your going to pay for it. Changing two styles on two elements is extremely expensive.
  • Know the difference between keyCodes for key events during keypress and keyup. They are different. Also, SlimBrowser with ie will override your key commands if you happen to try to override them yourself (say, by disabling f5 for refresh)
5. Try these, in general.
  • In ie, use line-height to vertically align elements, because vertical-align won't work. Just make line-height the same as height.
  • Always use Regular Expressions whenever possible to parse strings. Or use a stringbuilder that I found, which is extremely fast. (StringBuilder blog coming soon)
  • Enclosures are a wonderful thing. This is also a wonderful resource : A John Resig Book. If you know about Mr R., then you know its at least a book worth reading. I recommend you try to use enclosures when you must load something where, along the way, you will need to access local functions or variables later. Enclosures allow you to addEvents to objects with ease, amongst many other things - they help you make elegant code!
  • Work modularly. To help you work less procedurally and more modularly, try working with the JSON syntax. It is not only a great way to partition your work, it minimizes global variables, a more or less known evil. I also highly recommend this book Javascript: the good parts.
  • Sometimes browsers like IE highlight the screen with dark blue text? That is the selection mechanism. To confuse it, set the focus of any element on the page that can accept focus. Until you understand the bug you have at hand, focus() on an element is a fantastic way to short-circuit the natural browser behavior. Use it sparingly.

More to come.

No comments: