Steve M
Steve M

Reputation: 9794

clearInterval() and setInterval() when all animations are complete

I have a function that is repeatedly being called with setInterval creating animations. If there are still animations running I need it to stop calling the function until all the animations are complete. The code I am using is as follows:

EDIT: Added coded where I am removing the animated elements from the DOM, is that the problem?

var serviceLoop = setInterval(serviceQueue, LOOP_POLL_MS); //10 ms

function serviceQueue()
{
       //do some animations..
       function moveMan(from, to, plane)
      {
        (function() {

            var tmp_from = from;
            var tmp_to = to;
            var tmp_plane = plane;
            var pos = tmp_from.offset();
            var temp = tmp_from.clone(true);

            temp.css({ "visibility":"visible",
                "position":"absolute",
                "top":pos.top + "px",
                "left":pos.left + "px"});
           temp.appendTo("body");
           tmp_from.css("visibility", "hidden");
        //if (!tmp_plane) tmp_to.css("visibility", "hidden");
           temp.animate(to.offset(), moveMan.ANIMATION_TIME, function() {
                tmp_to.css("visibility", "visible");
                temp.remove();
           });
       })();
     }
       if ($(":animated").length > 0)
        {
            clearInterval(serviceLoop);
            $(":animated").promise().done(function() {
                serviceLoop = setInterval(serviceQueue, LOOP_POLL_MS);
            });
        }
}

The problem I am having is after a couple of animations the function passed to done() is never called, and the script stops.

Upvotes: 1

Views: 232

Answers (1)

jfriend00
jfriend00

Reputation: 708106

It seems likely that you end up waiting on a promise() that is waiting on some animations, but then you remove some of those objects from the DOM and then their animation never finishes so the promise never resolves.

See this quote from the jQuery doc for .promise():

Note: The returned Promise is linked to a Deferred object stored on the .data() for an element. Since the.remove() method removes the element's data as well as the element itself, it will prevent any of the element's unresolved Promises from resolving. If it is necessary to remove an element from the DOM before its Promise is resolved, use .detach() instead and follow with .removeData() after resolution.

One quick hack might be top call .stop(true) on any item that you are removing from the DOM.

In general, this code needs to be rewritten to be safe from that possibility and hopefully to rethink how you approach whatever it is you're trying to do every 10ms because that's generally a bad design. You should use events to trigger changes, not a 10ms polling operation. You have not explained the purpose of this code so it's not clear to me what alternative to suggest.

Upvotes: 1

Related Questions