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:

  • Why does the bouncing go out of sync occasionally?

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

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

  • Thanks for your help!


    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");
    });
    

  • 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

  • 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.

  • 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.


    如果你想使用JavaScript动画,你可以使用更好的东西,像绿叶补间库http://greensock.com/docs/#/HTML5/GSAP/TweenMax/to/这样的事情:

    var tween = TweenMax.to($("div"), 100, {y: "100px", yoyo: true, repeat: -1});
    
    链接地址: http://www.djcxy.com/p/89866.html

    上一篇: Haskell仆人和流媒体

    下一篇: 重复一段时间后,间隔不会立即清除