Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

delay for jquery promises

I cannot find delay or wait function for jQuery promises. I have found one function on the SO (Using jQuery.Deferred to avoid nested setTimeout callbacks):

function delay(time) {
    return function () {
        console.log("Delaying");
        var ret = new $.Deferred();
        setTimeout(function () {
            ret.resolve();
        }, time);
        return ret;
    };
}

And, it's the way how I use it:

 run: function () {
        return $()
            .promise()
            .then(function () {
                console.log("call together");
                console.log("call together");    
            })
            .then(delay(2000))
            .then(function () {
                console.log("call first");
            })
            .then(delay(2000))
            .then(function () {
                console.log("call second");
            })
    }

I want to extend promise or deferred object that I can write like:

run: function () {
            return $()
                .promise()
                .then(function () {
                    console.log("call together");
                    console.log("call together");    
                })
                .delay(2000)
                .then(function () {
                    console.log("call first");
                })
                .delay(2000)
                .then(function () {
                    console.log("call second");
                })
        }
like image 899
user348173 Avatar asked Jun 10 '15 04:06

user348173


People also ask

How do I add a delay to a Promise?

The built-in function setTimeout uses callbacks. Create a promise-based alternative. function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } delay(3000).

What does delay do in jQuery?

Added to jQuery in version 1.4, the . delay() method allows us to delay the execution of functions that follow it in the queue. It can be used with the standard effects queue or with a custom queue. Only subsequent events in a queue are delayed; for example this will not delay the no-arguments forms of .

How do I use setTimeout instead of Promise?

We can wrap setTimeout in a promise by using the then() method to return a Promise. The then() method takes upto two arguments that are callback functions for the success and failure conditions of the Promise. This function returns a promise.

Can you defer jQuery?

The jQuery. Deferred method can be passed an optional function, which is called just before the method returns and is passed the new deferred object as both the this object and as the first argument to the function. The called function can attach callbacks using deferred. then() , for example.


1 Answers

As @Bergi says jQuery Deferreds/Promises are not extendible by prototypal inheritance.

Instead, the model adopted by jQuery is to allow individual Promise instances to be extended with the syntax :

deferred.promise(target);
//or, 
promise.promise(target); //(though the documentation doesn't make this clear)
// where `target` is an "object onto which the promise methods have to be attached"
// see https://api.jquery.com/deferred.promise/

By defining a constructor with a bunch of methods, any jQuery Deferred or Promise can be extended with the simple syntax

.promise(Constructor())

In my unpublished, undocumented jQuery promises Playground, the constructor is named $P and kept in the jQuery namespace, hence the actual syntax I use is :

.promise($.$P())

You need to be aware of that, for the most part, it's not necessary to call $.$P() explicitly as the Playground includes a $.when_() method that returns an already extended Promise.

Here's an abbreviated version of the Playground with just enough to provide a .delay() method :

(function($) {
    /* ***********************************
     * The $.$P function returns an object
     * designed to be extended with 
     * promise methods using the syntax :
     *    myDeferred.promise($.$P())
     *    myPromise.promise($.$P())
     * where `myDeferred`/`myPromise` 
     * are jQuery Deferred/Promise objects.
     * ***********************************/

    /* ***********************************
     * Methods
     * ***********************************/
    $.$P = function() {
        if (this instanceof $.$P) {
            return this;
        } else {
            return new $.$P();
        }
    };
    $.$P.prototype.then_ = function(fa, fb) {
        /* A promise method that is the same as .then()
         * but makes these extra methods available 
         * down-chain.
         */
        return this.then(fa||null, fb||null).promise($.$P());
    }
    $.$P.prototype.delay_ = function(ms) {
        /* A promise method that 
         * introduces a down-chain delay.
         */
        var promise = this;
        function f(method) {
            return function() { setTimeout(function(){ method.apply(null,this); }.bind(arguments), ms||0); };
        }
        return $.Deferred(function(dfrd) { 
            promise.then(f(dfrd.resolve), f(dfrd.reject));
        }).promise($.$P());
    }

    /* ***********************************
     * Utility functions
     * ***********************************/
    function consolidate(args) {
        /* Convert mixed promises/arrays_of_promises to single array.
         * Called by all the when_() methods below.
         */
        return Array.prototype.slice.apply(args).reduce(function(arr, current) {
            return arr.concat(current);
        }, []);
    }

    /* ***********************************
     * This section extends the jQuery namespace 
     * with a "jQuery.when_()" method.
     * ***********************************
     */
    $.extend({
        'when_': function() {
            return $.when.apply(null, consolidate(arguments)).promise($.$P()).then_(function() {
                return consolidate(arguments);
            });
        },
    });
})(jQuery);

The full Playground also includes a whole bunch more static and promise-instance methods for other purposes, and developing them is the essence of the play.

The ground-rules for using the Playgound are as follows :

  • All the Playground's static and promise methods end in "_" underscore.
  • Static methods, eg $.when_(), are made available just by installing the Playgound.
  • Promises in a promise chain are extended by including a static method, eg .when_(), or chaining .promise($.$P()).
  • In a promise chain, the extensions remain available (down the chain) by using "..._" methods rather than the standard methods, eg .then_() in place of .then().

So here's how to use it to impose the delays required by the question :

jQuery(function($) {
    var MYNAMESPACE = {
        run: function (t) {
            return $.when_()
            .then_(function () {
                log("call together");
                log("call together");    
            })
            .delay_(t)
            .then_(function () {
                log("call first");
            })
            .delay_(t)
            .then_(function () {
                log("call second");
            });
        }
    }
});

DEMO

In the demo, the button's click handler gives further indication of how the Playground can be used.

Provisos on using the Playground :

  • As I say - it's a playground.
  • As an adaptor for jQuery, not a patch, it is horribly inefficient in places. Worst aspect is that some methods create an intermediate promise in addition to the one they return.
  • Not tested to the standards required for use in production code, so use with caution.

And lastly, only consider the above if you are determined to implement delay with jQuery. It's far far simpler to use a promise lib that already has a .delay() method.

like image 94
Roamer-1888 Avatar answered Sep 22 '22 15:09

Roamer-1888