cowboy / jquery-dotimeout

jQuery doTimeout: Like setTimeout, but better!
http://benalman.com/projects/jquery-dotimeout-plugin/
GNU General Public License v2.0
273 stars 34 forks source link

Problems when called from inside a handler #3

Open iangilman opened 12 years ago

iangilman commented 12 years ago

Great plugin! One issue:

In this example:

$.doTimeout("foo", 100, function() {
    log("in");
    $.doTimeout("foo", 1000, function() {
        log("out");
    });
});

... the inner doTimeout should clear away any others with the same ID, but it does not. Wrapping the inner doTimeout in a setTimeout fixes it, so I assume it has to do with setting up a new doTimeout from within its own handler.

Minimal test case:

http://jsfiddle.net/MmJwj/

I suppose it may look contrived, but it's from a real use-case; I can give more detail if needed.

Thanks.

cowboy commented 12 years ago

Can you describe, in plain english, what you're trying to do?

iangilman commented 12 years ago

Sure! The scenario is we have a magazine webapp, and as we're flipping through the pages, we want a little box to appear (after a small delay) and then disappear later (after a longer delay). The code above works fine if all you do is flip one page; you get "in" after 100ms, and then "out" 1000ms later.

If, however, you flip a number of pages quickly, we want the little box to stay up the entire time. With the code above, the box comes on when it's supposed to, but it disappears 1000ms later, even though there have been more recent $.doTimeout("foo", ...) calls in the intervening time. I was expecting that those intervening calls would have wiped clear the initial 1000ms timer, so the box only disappears 1000 ms after the last "in" rather than the first. If I add a setTimeout(..., 1) around that inner doTimeout, I get the result I was expecting.

Does that clarify?

cowboy commented 12 years ago

Ok, I looked at my code. It seems like I never accounted for a scenario in which the same id would be used in multiple overlapping timeouts. As a result, this isn't going to work unless I significantly refactor the code. Which I can't do right now, but will add to my list of future updates.

That being said, take a look at my Throttle/Debounce plugin. It should allow you to do pretty much what you're trying to do. See this example:

http://jsfiddle.net/cowboy/tJkX8/

iangilman commented 12 years ago

Thanks for the suggestion. Here's what I ended up going with:

clearTimeout(this.pageNumberTimeout);
this.pageNumberTimeout = setTimeout(function() {
    $pn.stop(true).fadeIn(); 
    self.pageNumberTimeout = setTimeout(function() {
        self.pageNumberTimeout = null;
        $pn.stop(true).fadeOut("slow");
    }, 3000);
}, 300);

... so no rush on fixing this bug on our account. I figure I'm probably not the only one who wants to do this sort of thing (I'll call it a "nested debounce"), so probably worth fixing at some point.

Thanks again for all the great libraries! We're using a few of them in our project, which includes the Playboy Archive webapp:

http://blog.iangilman.com/2011/05/making-iplayboy.html

... and the Rolling Stone Archive:

http://archive.rollingstone.com