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");
})
}
The built-in function setTimeout uses callbacks. Create a promise-based alternative. function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } delay(3000).
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 .
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.
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.
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 :
$.when_()
, are made available just by installing the Playgound..when_()
, or chaining .promise($.$P())
..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 :
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With