Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

Waiting for jQuery Animations: .promise(), .finish() and the Queue

C
Carlo Fontanos
· 2 min read

Every element in jQuery carries a hidden animation queue (named "fx"), and half the classic jQuery jank comes from not knowing it exists. The other half comes from coordinating "after the animation" logic with nested callbacks. Three methods fix both halves.

.promise(): animations meet async/await

// The 2010 way - callback pyramid
$('#panel').fadeOut(200, function () {
    $('#other').slideDown(200, function () {
        updateLayout();
    });
});

// The way that composes with everything else you write now
await $('#panel').fadeOut(200).promise();
await $('#other').slideDown(200).promise();
updateLayout();

.promise() resolves when the element's fx queue empties - and it's a real thenable, so await works. The underrated form is collections: it resolves when every matched element finishes, which is the "run after all the staggered cards land" primitive people hand-roll with counters:

$('.card').each((i, el) => $(el).delay(i * 60).fadeIn(200));
await $('.card').promise();          // ALL cards done, including the delays
enableInteractions();

// Mixing animations and AJAX in one gate
await Promise.all([
    $('#old-view').fadeOut(150).promise(),
    fetch('/api/data').then(r => r.json()),
]);

The queue-buildup bug and its two cures

Hover a naive accordion trigger ten times fast and it dutifully plays ten open/close cycles - animations queue by default. The cures differ in flavor:

$el.stop(true, true).slideToggle(200);   // clear queue, jump current anim to its end
$el.finish().slideToggle(200);           // clear queue AND finish everything instantly

.stop(clearQueue, jumpToEnd) with both flags true is the standard pre-animation guard for hover/click-driven effects. .finish() is stronger - it completes all queued animations' end states immediately - which makes it the tool for "user navigated away mid-sequence, snap everything to final state". The subtle difference: stop(true, true) only jumps the currently running animation to its end; queued-but-unstarted ones are discarded, potentially leaving intermediate CSS. finish() leaves the element exactly where the full sequence would have.

The queue is programmable, by the way

$el.fadeOut(200)
   .queue(function (next) {
       $el.text('Updated!');    // sneak non-animation work INTO the sequence
       next();                  // always call next() or the queue stalls forever
   })
   .fadeIn(200);

.queue() inserts arbitrary steps between animations - the forgotten next() being jQuery's most classic frozen-UI bug. Honest coda: new animation work belongs in CSS or the Web Animations API, but the jQuery in production isn't going anywhere this quarter - and jQuery code that awaits .promise() and guards with .stop(true, true) is jQuery code nobody complains about.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading