views:

967

answers:

5

I have some legacy javascript that freezes the tfoot/thead of a table and lets the body scroll, it works fine except in IE8 its very slow.

I traced the problem to reading the clientWidth property of a cell in the tfoot/thead... in ie6/7 and FireFox 1.5-3 it takes around 3ms to read the clientWidth property... in IE8 it takes over 200ms and longer when the number of cells in the table is increased.

Is this a known bug ? is there any work around or solution ?

+2  A: 

I was unable to find any documentation that this is a known bug. To improve performance, why not cache the clientWidth property and update the cache periodically? I.E if you code was:

var someValue = someElement.clientWidth + somethingElse;

Change that to:

// Note the following 3 lines use prototype
// To do this without prototype, create the function,
// create a closure out of it, and have the function
// repeatedly call itself using setTimeout() with a timeout of 1000
// milliseconds (or more/less depending on performance you need)
var updateCache = function() {
   this. clientWidthCache = $('someElement').clientWidth;
};
new PeriodicalExecuter(updateCache.bind(this),1);

var someValue = this.clientWidthCache + somethingElse
Josh
A: 

Your problem may be related to something else (and not only the clientwidth call): are your updating/resizing anyhting in your DOM while calling this function?

Your browser could be busy doing reflow on IE8, thus making clientwidth slower?

Brian Clozel
A: 

IE 8 has the ability to switch between IE versions and also there is a compatibility mode. Have you tried switching to Compatibility Mode? Does that make any difference?

G Berdal
Yes switching to compatibility mode makes it perform much better, however it breaks other parts of my UI because it does not render exactly like IE7. Was hoping for a solution that didn't involve using compatibility, it may be the only option though.
Element
I'm not saying it is the problem in your case, but last time I had rendering discrepancies between IE7 and IE8 I found that my code especially html/css had bugs. Compatibility mode seemed to solve the problem but I did'n want to accept that either. So I would probably start running the codes through validators. Who knows, you might missed something. - I did. ;)
G Berdal
+6  A: 

I've solved this problem if you are still interested. The solution is quite complex. Basically, you need to attach a simple HTC to the element and cache its clientWidth/Height.

The simple HTC looks like this:

<component lightweight="true">
<script>
window.clientWidth2[uniqueID]=clientWidth;
window.clientHeight2[uniqueID]=clientHeight;
</script>
</component>

You need to attach the HTC using CSS:

.my-table td {behavior: url(simple.htc);}

Remember that you only need to attach the behavior for IE8!

You then use some JavaScript to create getters for the cached values:

var WIDTH = "clientWidth",
    HEIGHT = "clientHeight";

if (8 == document.documentMode) {

  window.clientWidth2 = {};
  Object.defineProperty(Element.prototype, "clientWidth2", {
    get: function() {
      return window.clientWidth2[this.uniqueID] || this.clientWidth;
    }
  });

  window.clientHeight2 = {};
  Object.defineProperty(Element.prototype, "clientHeight2", {
    get: function() {
      return window.clientHeight2[this.uniqueID] || this.clientHeight;
    }
  });

  WIDTH = "clientWidth2";
  HEIGHT = "clientHeight2";
}

Notice that I created the constants WIDTH/HEIGHT. You should use these to get the width/height of your elements:

var width = element[WIDTH];

It's complicated but it works. I had the same problem as you, accessing clientWidth was incredibly slow. This solves the problem very well. It is still not as fast IE7 but it is back to being usable again.

Dean Edwards
wow.. it's Dean Edwards.. /me bows
meder
A: 

I though I had noticed a slow performance also when reading the width properties. And there may very well be.

However, I discovered that the main impact to performance in our app was that the function which was attached to the window's on resize event was itself somehow causing another resize which caused a cascading effect, though not an infinite loop. I realized this when i saw the call count for the function was orders of magnitude larger in IE8 than in IE7 (love the IE Developer Tool). I think the reason is that some activities on elements, like setting element widths perhaps, now cause a reflow in IE8 that did not do so in IE7.

I fixed it by setting the window's resize event to: resize="return myfunction();" instead of just resize="myfunction();" and making sure myfunction returned false;

I realize the original question is several months old but I figured I'd post my findings in case someone else can benefit.

Alex