Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Async callback function in jquery .done() not executing

Why does giving an async function as a callback function for a jQuery deferred.done() not work? i.e. Why does

jqueryObj.fadeTo("slow", 1)
    .promise().done(asyncFunc);

not work, but

jqueryObj.fadeTo("slow", 1)
    .promise().done(function() {
        asyncFunc();
    );

does?

(Also, note that jqueryObj.click(asyncFunc) does work.)


Example:

<h2>Title</h2>
<ul>
  <li>Item</li>
  <li>Item</li>
  ...
</ul>

After the title has finished faded in, each item of the list fades in, in order. The fade time is 20000 ms, but the delay between list items is 250 ms (so the next list item starts fading in while the previous is still ongoing).

JS:

var title = $("h2"),
    listItems = $("ul li");

function wait(delay) {
    return new Promise(function(resolve) {
        setTimeout(resolve, delay);
  });
}

async function reveal() {
    for (var i = 0; i < listItems.length; i++) {
        $(listItems[i]).fadeTo(2000, 1);
        await wait(250);
    }
}

title.fadeTo(500, 1)
    //.promise().done(reveal) doesn't work!
    .promise().done(function() {
        reveal();
    });

Here is a JSFiddle showing the desired effect. You can try swapping for the commented out line to see nothing happens. The commented out line is how you normally expect functions to work

like image 491
binaryfunt Avatar asked Jan 12 '18 13:01

binaryfunt


3 Answers

The problem is that prior to jQuery 3 , $.Deferred (jQuery promise api) was not Promises A+ compliant.

In order to pass a reference to an async function use then()(more standard promise method) instead of done() and use jQuery v3+

title.fadeTo(1000, 1).promise().then(reveal)

Working fiddle

like image 80
charlietfl Avatar answered Oct 23 '22 21:10

charlietfl


I am not totally sure that this is the reason, however, this is weird enough to be strongly suspect:

try this code:

$.isFunction(reveal); //returns false instead of true
like image 35
Kaddath Avatar answered Oct 23 '22 19:10

Kaddath


This is because jQuery prior to version 3 simply doesn't support async delegates

Your first code is equivalent of:

jqueryObj.fadeTo("slow", 1)
    .promise().done(async() => await asyncFunc());

and not the code you provided.

This code doesn't work as well and this is because when you check the jQuery sources - it checks for ($.type === 'function') when you are registering a delegate.

For async function the .type returned is 'object' and not a 'function' and therefore it fails.

like image 28
Adassko Avatar answered Oct 23 '22 20:10

Adassko