Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

callback function not executes unexpectedly

I have this function to execute a callback after the fade out animation of the textarea finishes:

function inputReset() {
  return new Promise((resolve) => {
    if (lastExtend === true) {
      return resolve();
    };
    console.log('inside inputReset');
    const textarea = $("textarea").first();
    textarea.fadeOut(1500, "swing", async() => {
      console.log('inside callback');
      await textareaAnimeEnded(textarea);
      console.log('after await textareaAnimeEnded(textarea)');
      return resolve();
    });
  });

  function textareaAnimeEnded(textarea) {
    console.log('inside textareaAnimeEnded');
    inputClear();
    textarea.fadeIn(0);
    Dots.show();
    return new Promise(resolve => setTimeout(() => resolve(), 500));
  }
}

But unexpectedly I only see the console.log('inside inputReset'); and although the fade out animation occures but I never get to the callback function (we never reach console.log('inside callback');)

What I'm missing?

like image 869
Sara Ree Avatar asked May 26 '26 20:05

Sara Ree


1 Answers

The confusion here is due to jQuery version mismatches. JQuery's isFunction check was updated in version 3.3.0 to accept async functions and generators.

fadeOut and other animation functions check the type of the callback argument. If it isn't a "function" (by jQuery's definition), then jQuery assumes no callback was passed.

The callback passed to fadeOut must therefore satisfy jQuery's definition of a function. And, unfortunately, before v3.3.0 that definition didn't include async functions or generators.

The check jQuery did before v3.3.0 was basically:

({}).toString.call(maybeFunction) === '[object Function]'

(actual algorithm here and here and used here by fadeOut and all other animations)

We can see that async functions and generators don't pass this check:

({}).toString.call(() => {}) // '[object Function]'
({}).toString.call(async () => {}) // '[object AsyncFunction]'
({}).toString.call(function*() {}) // '[object GeneratorFunction]'

However, with the new check added in v3.3.0:

typeof maybeFunction === 'function'

all of these pass:

typeof (() => {}) // 'function'
typeof (async () => {}) // 'function'
typeof function*() {} // 'function'

This is why in versions < 3.3.0 you see the animation working, but your async callback function is not called. JQuery doesn't recognize it as a function. In fact, if you omit the easing parameter, jQuery tries to set the passed async callback function as the animation's easing, which breaks jQuery:

textarea.fadeOut(2000, async () => {})
// jquery.js:6515 Uncaught (in promise) TypeError: jQuery.easing[this.easing] is not a function

for more nitty gritty details, read on:


The changelog in question is here:

Update isFunction to handle unusual-@@toStringTag input

The jQuery PR responsible for this change is here:

Generators and async functions are still functions, and we can recognize them with typeof

Most notably this line:

return jQuery.type( obj ) === "function"

got changed to (simplified):

return typeof obj === "function"
like image 193
bowheart Avatar answered May 28 '26 09:05

bowheart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!