My former employer, Cúram Software, was good enough to give me a couple of months to work on the performance issues that Dojo and it’s widget project Dijit have in horrible legacy browsers IE6 and IE7. Some of the fruits of that labour have now been checked into the code base and will be included in Dojo 1.6, out in Q4 2010.
So what I/we learned from the exercise?
To begin with, I can’t praise DynaTrace enough. It’s a fantastic piece of profiling software that delves deep into Internet Explorer’s innards to find every little horrible Microsoft bug. It can take a while to get used to, but that is just because it presents you with so much data, all of it useful, and anyone would have trouble finding a way to make it easily consumable. Long story short, if you’re having performance issues with your site in IE, download DynaTrace.
Touching className makes IE cry
Pretty much every time you change the className property of a node, IE6 and IE7 reflow the page. It doesn’t matter if the new value is the same as the old one, or whether or not the changed CSS class has any visual effect, IE will redraw the page, resulting in a lot of time being lost.
Dojo was changing className too often, for example in dojo.addClass, if the class being added was already present, it would still assign the changed value to className. I put a fix for this into v1.5. There were also many cases where Dojo would use a combination of dojo.removeClass and dojo.addClass to replace a class, which changed className twice instead of just once. To fix this, I’ve added a new public api dojo.replaceClass, which only changes className once.
Dijit widgets often add CSS classes to the DOM nodes which they are creating after the nodes have been inserted into the document. This is costly, and a large performance improvement can be gained by applying these classes earlier in the lifecycle, before inserting into the document. Bill Keese (Dijit master) checked in the first of the fixes for this for the BorderContainer recently, and a strategy is being formulated for the many other widgets that can benefit from this. This work should be completed for v1.6.
A solution that we cannot use for Dojo, but which we found gave huge performance gains for my company’s application, was to figure out what CSS classes Dojo would apply to a node and write those classes out when generating the HTML. For example, when creating a dijit.layout.BorderContainer, our HTML contains the CSS class dijitBorderContainer. There is an inherent risk with this approach, as Dojo may change the CSS classes in a later release, but if you’re willing to accept the risk and the upgrade pain, you can get a nice performance boost this way.
Reading offsetLeft and offsetTop is costly
When your code reads the offsetLeft or offsetTop of a node, all pending changes to the DOM have to be performed first. This can be very expensive – we saw a number of single operations taking over 500ms each! Many Dijits were using the dojo.marginBox method to get the left, top, width and height properties of a node, when all they needed was the width and height.
To solve this, I introduced a new method, dojo._getMarginSize, a private method that just returns the width and height of a node. This has resulted in huge gains in performance on IE6 & 7, especially when used with layout widgets like the BorderContainer.
Unexplained gaps in DynaTrace profiles
We hit a bit of a wall at one point when analysing the performance profiles, where there was a 1.5 second gap in the profile where it seemed like nothing was happening, but everything was paused with the CPU at 100%.
We eventually discovered that there is a horrible bug in IE7 where if you have a :hover style on something that is not an anchor tag, it causes the rendering engine to go crazy, get all confused, and push the CPU up to 100% for no reason at all.
The solution: don’t user :hover styles on anything other than <a> tags. Ridiculous I know, but so is the IE7 rendering engine.
Give it a go!
So, the long and short of it is that Dojo/Dijit should now be a good bit snappier on IE6 and 7. With our application we got the load time for a huge application down from 20 seconds to 5 seconds using these techniques, making IE7 far, far more usable. Of course it just flies on any other browser, even IE8 which, all credit to MS for once, is far less buggy than the earlier incarnations.
So feel free to try out the Dojo nightlies, you should find them to be a good bit more responsive in IE6 and 7 than just a few days ago, and now that we have learned some important lessons, Dojo will be even faster for v1.6.