1
\$\begingroup\$

I've just started programming with JavaScript and I am currently working on this hobby website project of mine. The site is supposed to display pages filled with product images than can be "panned" to either the left or right. Each "page" containing about 24 medium sized pictures, one page almost completely fills out an entire screen. When the user chooses to look at the next page he needs to click'n'drag to the left (for example) to let a new page (dynamically loaded through an AJAX script) slides into the view.

This requires for my JavaScript to "slide" two of these mentioned pages synchronously by the width of a screen. This results in a really low framerate. Firefox and Opera lag a bit, Chrome has it especially bad: 1 frame of animation takes approx. 100 milliseconds, thus making the animation look very "laggy".

I do not use jQuery, nor do I want to use it or any other library to "do the work for me". At least not until I know for sure that what I am trying to do can not be done with a couple of lines of self-written code.

So far I have figured out that the specific way I manipulate the DOM is causing the performance-drop. The routine looks like this:

function slide(){
this.t=new Date().getTime()-this.msBase;

if(this.t>this.msDura)
{
this.callB.call(this.ref,this.nFrames);
return false;
}

//calculating the displacement of both elements
//
this.pxProg=this.tRatio*this.t;

this.eA.style.left=(this.pxBaseA+this.pxProg)+'px';
this.eB.style.left=(this.pxBaseB+this.pxProg)+'px';

if(bRequestAnimationStatus)requestAnimationFrame(slide.bind(this));
else window.setTimeout(slide.bind(this),16);

this.nFrames++;

};

...

//starting an animation
//
slide.call({ 'eA':theMiddlePage,
'eB':neighboorPage, 
'callB':theCallback,
'msBase':new Date().getTime(),
'msDura':400,
'tRatio':((0-pxScreenWidth)/400),
'nFrames':0,
'ref':myObject,
'pxBaseA':theMiddlePage.offsetLeft,
'pxBaseB':neighboorPage.offsetLeft
        });

I've noticed that when I let the AJAX script load less images into each page, the animation becomes much faster. The separate images seem to create more overhead than I have expected. Is there another way to do this?

(Reposted from Stack Overflow here)

\$\endgroup\$
1
\$\begingroup\$

Well I can only guess without seeing the code where the DOM is actually accessed but one thing that looks big to me is that you appear to be manipulating each individual element in seperate frames. If you did the calcs in one function for all elements that would be (I believe) one set of reflow calcs set off in the browser rather than per elements-moved.

Basically any time there is a change to the DOM a series of reflow calculations is set off in the browser. I think when say three DOM changes are made in one function call, the browser is aware of all three before it starts doing anything. Whereas with seperate funcs it does that same work multiple times.

How much reflow calculation gets set off for an action on the DOM in any given browser isn't something I'm a real wizard on but IIRC tends to be a fairly crude operation that doesn't necessarily take "out of flow" elements like absolutely positioned containers into consideration. That said, I still tend to find the DOM seems to have an easier time of it when you try to optimize by taking movable elements out of flow first.

If you don't need to support older browsers, look into CSS3 animation approaches. These can drastically improve animation performance since browsers can optimize for actions before they happen.

Barring that, avoid touching the DOM as much as possible in loops. If you must access properties on a DOM element multiple times, don't keep reacquiring it. Assign it to a var, effectively caching that operation (note: might not matter in newer browsers). But actually making changes to the DOM is where you need to optimize the most. Sidestep with pre-set CSS3 animations or follow some of the older-school stuff I've outlined here and we can examine in more depth if needed.

\$\endgroup\$
  • \$\begingroup\$ yes, Jude Osborn pointed out CSS3 animations to me as well. Currently checking out the "transition" attribute. This looks like it might be the solution to my problem. \$\endgroup\$ – John Smith Mar 7 '13 at 23:46
  • \$\begingroup\$ Yep, just track minimum IE support for whatever css3 properties you use. I don't think they even touched CSS3 support until IE9. The ideal way to handle it is old-school and new-school depending on what's available. \$\endgroup\$ – Erik Reppen Mar 7 '13 at 23:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.