jQuery delay() not working for you?

jQuery’s delay() function causes more than its fair share of problems over on Stack Overflow. You often see people trying to use delay() to delay something like* setting a CSS property (via css()), and then wondering why their CSS property updated immediately; irrespective of their use of delay().

$('#some-element').delay(5000).css("backgroundColor", "red"); // this won't work

*: Other common problems originate from trying to perform DOM manipulation (via the likes of append(), after() etc, or the setting of HTML/ values (via html(),text() or val()).

The short answer is to basically use setTimeout() instead. The long answer involves looking more into how jQuery queues these requests, and finding out exactly what delay() does…

Why it doesn’t work…

When you call delay(5000), what you’re actually doing is calling delay(5000, "fx") as the function has an optional second parameter (the queue name you wish to delay operation of) which defaults to fx. The various effects methods (fadeOut(), animate() etc.) all use this queue which is why delay() has an effect on them.

However nothing else in jQuery does (by default at least, but we’ll get to that part shortly). That is to say that calls to any manipulation functions (html(), append(), css() etc.) will completely ignore your delay() call, because they’re are all executed immediately, and not queued at all.

How you can fix it…

The recommendation here is to use setTimeout() instead; your code will end up looking like this:

setTimeout(function () {
    $("#some-element").css("backgroundColor", "red");
}, 5000);

However, if you wish to use delay(), you can use the queue() function to queue something. The signature of the queue() function is as follows;

queue([queueName,] functionToBeExecuted(next));

That is to say, the first argument is the name of the queue you wish to add to (which defaults to fx when not specified), and the second argument is the function you wish to queue. That function gets passed one parameter, which you must call when your function has finished doing whatever it needs to do; this is to ensure the next elements in the queue get executed as well.

Therefore we end up doing something like this;

$('#some-element').delay(5000, "my-queue").queue("my-queue", function (next) {
    $(this).css("backgroundColor", "red");
    next();
});

Note that in the above example, we’ve specifically avoided the fx queue; the changing of the background-color is not related to fx at all, so we shouldn’t abuse the use of that queue. Having said that, there are times when queuing to the fx queue is useful; such as when you want to perform an action after a list of effects have completed;

$("#some-element").fadeIn(200).animate({
    padding: "+=50"
}, 1500).delay(1000).queue(function (next) {
    $(this).css("backgroundColor", "red");
    next();
});

Of course, if we wanted to be very explicit about which queues we were using, it’d look something like this:

$("#some-element").fadeIn(200).animate({
    padding: "+=50"
}, 1500).delay(1000, "fx").queue("fx", function (next) {
    $(this).css("backgroundColor", "red");
    next();
});

For further reading after finishing the article, consider reading the delay() documentation or the Stack Overflow question that triggered me writing this article!

5 thoughts on “jQuery delay() not working for you?

  1. Thank you thank you thank you!! The documentation on the jQuery site it confusing and inadequate. Been trying to delay a hover effect for weeks now and thanks to you it’s finally working with some very simple code.

    .linger {
      display:block !important;
    }
    $(document).ready(function(){
    	$('ul.nav-child').mouseout(function(){
    		$(this).addClass('linger');
    		setTimeout(function(){
    			$('ul.nav-child').removeClass('linger');
    		},1000);
    	});
    });

    Thank you again.

  2. Thank you!
    I don’t get the “function(next)” part, is this “next” a preserve word in jquery? or it can be replaced by any word? what does next() do? Is it different from .next()?
    And if next() is always required, than as smart as jQuery is, why don’t it just integrate it into the method instead of requiring us repeatedly to write it?

  3. Hi Shenkwen,

    jQuery passes a function as a parameter to the function you en-queue. I’ve named it “next” in my examples, but you can replace it with any word as you thought. Your function needs to call “next” when it has finished it’s work. This lets jQuery continue to process any other functions in the queue.

    jQuery can’t integrate the method because you might use setTimeout/ make an AJAX call/ carry out some other asynchronous work in your function; jQuery can’t detect this, so instead relies on you to tell it when you’re done using next().

    Cheers,
    Matt

  4. Loved it! Was very helpful and I found this only here and not anywhere else in the internet. Appreciations to you! 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *