Search code examples
javascriptjquerypromisejquery-deferred

Converting a jQuery Deferred Promise to a native JavaScript Promise


I plucked this JavaScript code below out of a library and it uses jQuery's Deferred/promises which are not the same as the official Promise spec.

I would like to convert this basic example into a Native JavaScript Promise while keeping the same format/structure below.

Almost every example Promise usage I find online is of loading something asynchronously and I have some cases where I would like to use them for other tasks and this example does just that!

  • App.show() is called
  • App.show() calls a function that returns a Promise App.Animations.swipe.apply(this, [current, next, dir]).then(finalize);
  • The promise function has an event handler function inside it that runs when a CSS animation is completed and that triggers the Promise to resolve.
  • When the promise resolves it then calls the finalize function that is inside of the App.show() function.

It might be easier to follow what it does by simply looking at the example below....

var App = {

  show: function(index, direction) {
    var $this = this;

    // called after Promise is resolved with .then(finalize)
    finalize = function() {
      // other code here ran now after promise resolved from App.Animations.swipe()....
    };

    // call function which returns a Promise
    Animations.swipe.apply(this, [current, next, dir]).then(finalize);
  },


  Animations = {

    'none': function() {
      var d = UI.$.Deferred();
      d.resolve();
      return d.promise();
    },

    // function returns a Promise which has an event handler inside it that resolves the promise
    'swipe': function(current, next, dir) {

      var d = UI.$.Deferred();

      next.css('animation-duration', this.options.duration + 'ms');

      // Event handler ran one time when CSS Animation ends and triggers the event
      // this event is what resolves the promise
      next.css('opacity', 1).one(UI.support.animation.end, function() {

        current.removeClass(dir === -1 ? 'uk-slideshow-swipe-backward-out' : 'uk-slideshow-swipe-forward-out');
        next.css('opacity', '').removeClass(dir === -1 ? 'uk-slideshow-swipe-backward-in' : 'uk-slideshow-swipe-forward-in');
        d.resolve();

      }.bind(this));

      // return a Promise Object when this function is called
      return d.promise();
    },
  }
};

So based on that code how can it be converted to not use jQuery's Deferred and use native JS Promises?


Solution

  • 'none': function() {
      var d = UI.$.Deferred();
      d.resolve();
      return d.promise();
    },
    

    That's a simple one

    'none': function() {
        return Promise.resolve();
    },
    

    Now for swipe:

    'swipe': function(current, next, dir) {
      return new Promise(function(resolve, reject) {
        next.css('animation-duration', this.options.duration + 'ms');
    
        // Event handler ran one time when CSS Animation ends and triggers the event
        // this event is what resolves the promise
        next.css('opacity', 1).one(UI.support.animation.end, function() {
    
          current.removeClass(dir === -1 ? 'uk-slideshow-swipe-backward-out' : 'uk-slideshow-swipe-forward-out');
          next.css('opacity', '').removeClass(dir === -1 ? 'uk-slideshow-swipe-backward-in' : 'uk-slideshow-swipe-forward-in');
          resolve();
    
        }.bind(this));
    },
    

    Notes

    I just want to add that jQuery Promises (or Deferreds as they call them) were at one stage kind of broken, but these days I think they are compliant with Promise/A+ spec.

    Many jQuery functions (ajax, animations for example) return a promise, or you can return .promise() - which negates the need for what I've done in the answer, and that is to use a promise constructor anti-pattern.

    I'm not sure enough about your code to know if any of those jQuery methods can return a promise or not.