views:

273

answers:

3

Lately I've been spending some time reading about jQuery optimization tips which has certainly helped increase the performance of my scripts.

However, I've got this featured news section on my site, which on mouse hover slides more information into place, and this section doesn't perform very well in any browser except Safari (and probably Chrome too, then.)

The reason for this, I believe, is that it's doing quite some DOM traversing and calculations on every mouseover/mouseout event before animating.

My question is simple: Is there any way to optimize the code below so that the animation runs more smoothly?

$('#featuredSide .featuredBox,#featuredBottom .featuredBox,#archiveVideos .featuredBox').hover(function(){ 
var boxHeight = parseInt($(this).css('height'))-8;
var bottomOrSide = $(this).parents("div[id^='featured']").attr("id")
var captionPos = 76;
var captionHeight = parseInt($(this).find(".videoCaption").css('height'));
var animateTo = boxHeight-captionHeight;

$(".videoCaption", this).stop().animate({top:animateTo + 'px'},{queue:false,duration:160});
}, function() {
$(".videoCaption", this).stop().animate({top:captionPos},{queue:false,duration:100});
});

Since the site I'm working on hasn't been published yet I've uploaded a screenshot of the news section to give you an idea of what it looks like.

Thanks!

+1  A: 

You do some of the work several times over, which will be hurting you. How much is hard to say, but try this...

var el = $(this);
var vid = $(".videoCaption", this);
// use el.blar() instead of $(this) and vid.blar() instead of $(".videoCaption", this).blar()

It also looks like your dom structure must be different in all the different locations that this panel is used, as your code seems to have to do a fair bit of work to find the appropriate bits of dom to use. If possible, I would recommend making the DOM structure the same in all the different locations, and then making use of that structure in the code.

If that isn't possible, try coding a unique version of this function for each location - not ideal, but if it solves your performance problem it might be worth it.

rikh
Excellent suggestions — thanks!Related follow-up question: Since starting with jQuery I've always wondered about whether providing a shorter or longer duration on the animations will have any impact on speed and performance.Is there a set answer to this? Will fadeOut("fast") be faster or slower than fadeOut("slow")?
heintore
I don't think so. In both cases I think it will be updating the opacity of the element and refreshing the page as fast as the browser will allow. Faster browsers will just squeeze more steps in, resulting in a smoother animation.
rikh
+2  A: 

For starter, it is possible to do Common subexpression elimination, so for example instead of calling

$(this)

multiple times, store that object in a variable and use that variable instead.

var current = $(this);

On the other hand, single use variables can be inlined. Some may call them premature optimization, but since it is already stated that the code is slow, I don't think it's premature.

The bottomOrSide variable doesn't seem to be used there.

As for the selector, it is possible to replace the whole long thing with this?

$('.featuredBox')
RichN
In my tiny little head I imagined that my selectors would be faster due to limiting the scope, but this might not apply in this particular case?
heintore
I would expect a simple `.featuredBox` selector to perform faster in this situation - but, as always, _benchmark_ it if you want to know!
Alex Barrett
That particular selector will not be slowing down your hover animations, by the way; the selector only seems to be being executed once.
Alex Barrett
@Alex Barrett: yeah, I guess that last one was not so important. On the other hand, specifying ID and class seems redundant, are they both needed?
RichN
Thanks Alex, I'll try and see if my friend FireBug can give a clear answer to the selector question :-)
heintore
+2  A: 

Another solution would be to memoize all calculation.

Don't call hover directly, use "each", calculate, and then apply the "hover".
Thus (I tried to change the code as little as possible):

$('#featuredSide .featuredBox,#featuredBottom .featuredBox,#archiveVideos .featuredBox').each(function(){ 
  var boxHeight = parseInt($(this).css('height'))-8;
  var bottomOrSide = $(this).parents("div[id^='featured']").attr("id")
  var captionPos = 76;
  var captionHeight = parseInt($(this).find(".videoCaption").css('height'));
  var animateTo = boxHeight-captionHeight;

  var params = {top:animateTo + 'px'};
  var options = {queue:false,duration:160};
  var target = $(".videoCaption", this);

  $(this).hover(function () {
    target.stop().animate(params, options);
  });
}

This solution would make my previous answer somewhat moot (they won't matter much, although still applicable). Remember to profile, though.

RichN
This is quite an elegant solution. I'll certainly try and see if it yields better results performance-wise.Thanks — again!
heintore