Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interval doesn't clear immediately after repeating for a while

I have a bouncing arrow on my website that I created with Jquery and setInterval, like this:

bouncing = setInterval(function() {
    $("div").animate({
        top:"30px"
    },100,"easeInCubic",function() {
        $("div").animate({
            top:"0px"
        },100,"easeOutCubic");
    });
    console.log("bounced");
},200);

You can see this in place in a codepen here: http://codepen.io/mcheah/pen/wMmowr

I made it run faster than i needed because its easier to see the issues quicker. My issue is that after leaving the interval running for a few seconds, you'll notice that instead of bouncing back up or down immediately, the bouncing element will stop for half a second and then just hang there, before beginning again. If you leave it running even longer (20 seconds) and then clear the interval, you'll notice that it takes a few seconds to stop bouncing.

My questions are these:

  1. Why does the bouncing go out of sync occasionally?

  2. Why does the clear interval take a while to clear if it's been repeating for a while?

  3. Is there a better way to have a bouncing arrow? Are CSS transitions more reliable?

Thanks for your help!

like image 892
mcheah Avatar asked Jan 25 '16 22:01

mcheah


People also ask

How do you stop intervals after some time?

To stop it after running a set number of times, just add a counter to the interval, then when it reached that number clear it. e.g.

Does setInterval call function immediately?

The setInterval() method calls a function at specified intervals (in milliseconds). The setInterval() method continues calling the function until clearInterval() is called, or the window is closed. 1 second = 1000 milliseconds.

Which of the following can be used to execute a function over and over again at specified time intervals?

The window object allows execution of code at specified time intervals. These time intervals are called timing events. Executes a function, after waiting a specified number of milliseconds.

Does setInterval affect performance?

Not appreciably. You'd have to be doing something extremely heavy in each interval for it to affect performance, and that would be true without setInterval involved at all.


2 Answers

Your are trying to perfectly coordinate a setInterval() timer and two jQuery animations such that the two come out perfectly coordinated. This is asking for trouble and the two may drift apart over time so it is considered a poor design pattern.

If, instead, you just use the completion of the second animation to restart the first and make your repeat like that, then you have perfect coordination every time.

You can see that here in another version of your codepen: http://codepen.io/anon/pen/NxYeyd

function run() {
    var self = $("div");
    if (self.data("stop")) return;
    self.animate({top:"30px"},100, "easeInCubic")
        .animate({top:"0px"}, 100, "easeOutCubic", run);
}

run();


$("div").click(function() {
    // toggle animation
    var self = $(this);
    // invert setting to start/stop
    self.data("stop", !self.data("stop"));
    run();
    console.log("toggled bouncing");
});
like image 62
jfriend00 Avatar answered Sep 28 '22 16:09

jfriend00


  1. It's not a good idea to mix animate() with timers this way. There's NO chance you can synchronize something like this. And there's no need to. You can simply append a function into the animation queue, look here: https://stackoverflow.com/a/11764283/3227403

  2. What animate() does is put an animation request into a job queue which will be processed later, when the right time comes. When you break the interval the stuff that accumulated in the queue will still be processed. There's a method to clear the queue and stop all animation immediately.

  3. The JQuery animation functions actually manipulate CSS, and there is nothing beyond it in HTML. Another option would be using a canvas, but it is a completely different approach and I wouldn't recommend it. With JQuery's animation your already at the best choice.

This is a simple solution to your problem:

function bounce()
{
  $("div")
    .animate({
      top: "30px"
    }, 100, "easeInCubic")
    .animate({
      top: "0px"
    }, 100, "easeOutCubic", bounce); // this loops the animation
}

Start bouncing on page load with:

$(bounce);

Stop bouncing on click with:

$("div").click(function() {
  $("div").stop().clearQueue().css({ top: "0px" });
  // you want to reset the style because it can stop midway
});

EDIT: there were some inaccuracies I corrected now. The running example is on codepen now.

like image 20
pid Avatar answered Sep 28 '22 15:09

pid