Oli
Oli

Reputation: 239810

How to interrupt previous event triggers in jQuery

So I've got a scroll event. It does a load of stuff to work out whether something should be moved on the page. When you scroll down, it fires off. If you wheel down, drag, it fires of bazillions and bazillions of times. As you'd expect, perhaps. Here's some simple dummy code to represent the sequence of events.

function scroller() {
    // 1. A really expensive calculation that depends on the scroll position
    // 2. Another expensive calculation to work out where should be now
    // 3. Stop current animations
    // 4. Animate an object to new position based on 1 and 2
}
$(window).on('resize' scroller);

Don't get me wrong, it's usually accurate so there isn't so much a concurrency issue. My animations inside the event call .stop() (as part #3) so the latest version is always* the right one but it's eating up a lot of CPU. I'd like to be a responsible developer here, not expecting every user to have a quad core i7.

So to my question... Can I kill off previous calls to my method from a particular event handler? Is there any way I can interfere with this stack of queued/parallel-running "processes" so that when a new one is added to the stack, the old ones are terminated instantly? I'm sure there's a concurrency-minded way of wording this but I can't think of it.

*At least I think that's the case - if the calculations took longer in an earlier run, their animation could be the last one to be called and could cock up the entire run! Hmm. I hadn't thought about that before thinking about it here. Another reason to stop the previous iterations immediately!

Upvotes: 1

Views: 120

Answers (1)

karim79
karim79

Reputation: 342635

You can ensure the event is fired a maximum of once per x milliseconds. E.g.:

(function ($) {
    $.fn.delayEvent = function (event, callback, ms) {
        var whichjQuery = parseFloat($().jquery, 10)
            , bindMethod = whichjQuery > 1.7 ? "on" : "bind"
            , timer = 0;
        $(this)[bindMethod](event, function (event) {                   
            clearTimeout (timer);
            timer = setTimeout($.proxy(callback, this, event), ms);
        });
        return $(this);
    };
})(jQuery);

$(window).delayEvent("resize", scroller, 1000);

Minimalistic demo: http://jsfiddle.net/karim79/z2Qhz/6/

Upvotes: 2

Related Questions