3

I know about the :animated selector, but currently am running into (what might be one of a few) performance issue for older IE's (go figure). I feel like it might potentially be the way I'm testing for ANY Page Animation.

Currently I'm looping through an interval, with the core test being $('*').is(':animated'). This $('*') is what i'm worried about... but since I don't know exaclty what the divs / etc are that are being animated below my plugin, I'm not sure how else to do it!

var testAnimationInterval = setInterval(function () {

    if ( ! $('*').is(':animated') ) {  // all done animating
        clearInterval(testAnimationInterval);

        animationsFinished();  // callback function
    }
}, 300);

function animationsFinished() {
    // do whatever
}

Has anyone found a better / different way of doing this? Especially when it comes to performance?

Mark Pieszak - Trilon.io
  • 44,537
  • 13
  • 74
  • 89
  • I don't know, that would be hard to catch everything. Especially since a lot of libraries/plugins append something to the ``, so you might need a very generic selector as `*`. Is there any way you know of specific areas on your page that animations might be taking place? Or do you have no idea? – Ian Jan 08 '13 at 15:30
  • I could potentially get the general div area, would that still be able to detect any/all animations occurring inside of it? – Mark Pieszak - Trilon.io Jan 08 '13 at 15:32
  • Doing a `$("*")` every 300ms is going to be a big performance hit on any browser. If you are in charge of setting the animation effects, keep track of them yourself. – cloakedninjas Jan 08 '13 at 15:35
  • @mcpDESIGNS Yeah, you'd check something like `$("#general_div_area").find(":animated").length` or maybe `$("#general_div_area").find("*").is(":animated")` – Ian Jan 08 '13 at 15:39
  • You would probably be slightly better off with `$(":animated").length` if you wanted to stay away from undocumented methods, however the undocumented method is MUCH faster than using the `:animated` selector because you're simply checking the length property on an array. http://jsperf.com/animated-jquery I doubt that undocumented array will be going anywhere soon. – Kevin B Jan 08 '13 at 15:58
  • @mcpDESIGNS: could you post the jsperf url? I'm curious what the difference is. – Cerbrus Jan 08 '13 at 16:19
  • 1
    @Cerbrus http://www.jsperf.com/animated-jquery - all 3 ways, head to head. – Mark Pieszak - Trilon.io Jan 08 '13 at 16:20

2 Answers2

6

All jQuery animation timers are stored in the array $.timers. One option is just to check whether length of $.timers property is more than zero:

if ($.timers.length > 0) {
    // something is animating
}
VisioN
  • 132,029
  • 27
  • 254
  • 262
  • Is `$.timers` part of jQuery or a plugin? I'm not seeing it in the jQuery documentation. – T. Junghans Jan 08 '13 at 15:39
  • 4
    @TJ. It is not documented property of jQuery. You can find it in the source code: https://github.com/jquery/jquery/blob/master/src/effects.js#L715. – VisioN Jan 08 '13 at 15:40
  • Ah, so you're the reason I'm getting mercilessly downvoted. Shun the answer that manually implements something that jQuery apparently sortof has, right? :P _(Disclaimer: the preceding statement is a joke. Good on you for finding that in the jQuery source)_ – Cerbrus Jan 08 '13 at 15:42
  • 1
    @Cerbrus I supposed jQuery must have something like that, otherwise how `:animated` selector works :) BTW, stupid dvotes is a real problem of SO. – VisioN Jan 08 '13 at 15:50
  • Yea, the downvotes can be rather silly at times. I mean, not to brag or anything, but my answer does show the basic idea of what to do. It's just that jQuery happens to have a simple way to get the counter -.- _"OMG Downvote!!!"_ – Cerbrus Jan 08 '13 at 15:54
  • 1
    @VisioN Damn you VisioN... spot on again :) As -KevinB pointed out (http://jsperf.com/animated-jquery) this one is **crazy** fast in comparison! Didn't know about this hidden internal jQuery gem. Thanks again brotha. – Mark Pieszak - Trilon.io Jan 08 '13 at 16:14
  • 1
    +1 good catch. This is interesting, though, that this property is undocumented. – inhan Jan 08 '13 at 16:27
0

I think it would be more efficient to push your element to an array when the animation starts, and remove it from the array when it's done animating. Or better yet, increment a variable on animation start, and decrease it by 1, when it's done. If the variable is 0, no animation should currently be running.

So, some pseudocode:

var animatingElements = 0;

function animationStart(){ // Add this function in your animation start events;
    animatingElements++;
}

function animationEnd(){ // Add this function  in your animation end events;
    animatingElements--;
}

if (animatingElements === 0) {
    clearInterval(testAnimationInterval);
}

This is, assuming you have access to the code that starts / catches the end of your animations, of course.

Cerbrus
  • 60,471
  • 15
  • 115
  • 132
  • How does this catch an animation by an external library? – Ian Jan 08 '13 at 15:40
  • You're telling that library to start animating, _somewhere_. `animationStart()` there. – Cerbrus Jan 08 '13 at 15:42
  • Yeah, not always. A simple, quick example is the jQuery UI "Autocomplete". I don't see any support for what to do when the results are being shown/hidden. While the results are simply shown/hidden (not exactly an animation), maybe in some scenario they could be faded in/out. Either way, there's no support for that, and not all libraries do support that. Assuming you are directly triggering an animation or have support to do something right before and right after it, isn't enough – Ian Jan 08 '13 at 16:13
  • 1
    @Cerbrus I like the idea, but I can't make any edits to the underlying page unfortunately! But next time, or when I can make updates to it, I'll start storing them in an Array no doubt. (Just for reference purposes at the very least) +1 – Mark Pieszak - Trilon.io Jan 08 '13 at 16:15
  • @mcpDESIGNS: Thanks ^_^ I'm glad I could be of some help, even though jQuery's got the timers array :P – Cerbrus Jan 09 '13 at 07:22