Delay for jquery promises

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

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

And this is the way 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 a promise or a pending object that I can write, for example:

 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"); }) } 
+5
source share
3 answers

As @Bergi writes, jQuery Deferreds / Promises do not expand by prototype inheritance.

Instead, the model adopted by jQuery should allow individual Promise instances to expand using 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 set of methods, any jQuery Deferred or Promise can be extended using simple syntax

 .promise(Constructor()) 

In my unpublished undocumented jQuery promises playground, the constructor has the name $P and is stored in the jQuery namespace, so the actual syntax I use is:

 .promise($.$P()) 

You should be aware of this, for the most part, you do not need to explicitly call $.$P() , since the Playground includes the $.when_() method, which returns an already extended promise.

Here's a shortened version of the playground with enough to provide the .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); 

A full playground also includes a whole bunch of more static and promising methods for other purposes, and their development is the essence of the game.

The basic rules for using Playgound are as follows:

  • All static and promising methods for playgrounds end with an underscore "_".
  • Static methods, such as $.when_() , are only available when installing Playgound.
  • Promises in the promise chain are expanded to include a static method, such as .when_() , or a chain of .promise($.$P()) .
  • In the promise chain, extensions remain available (down the chain) using the "..." methods, rather than standard methods such as .then_() instead of .then() .

So how to use this 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 click handler provides additional guidance on how to use the Playground.

Provisos when using the playground:

  • As I said, this is a playground.
  • As an adapter for jQuery, not a patch, it is terribly inefficient in various places. The worst aspect is that some methods create an intermediate promise in addition to the one they return.
  • Not tested for standards required for use in production code, so use with caution.

And finally, consider only the above if you decide to implement the delay using jQuery. It's much easier to use the lib promise, which already has a .delay() method.

+3
source

Change, update

Try adding delay property to jQuery.Deferred

  delay: function(t) { return this.then(function() { var args = arguments; return new $.Deferred(function(d) { setTimeout(function() { // return `data`, if any, to next method, eg, `.then`, in chain d.resolveWith(this, args) }.bind(this), t || 0) }).promise() }) } 

 (function($) { $.Deferred = function(a) { var b = [ ["resolve", "done", $.Callbacks("once memory"), "resolved"], ["reject", "fail", $.Callbacks("once memory"), "rejected"], ["notify", "progress", $.Callbacks("memory")] ], c = "pending", d = { delay: function(t) { return this.then(function() { var args = arguments; return new $.Deferred(function(d) { setTimeout(function() { // return `data`, if any, to next method, eg, `.then`, in chain d.resolveWith(this, args) }.bind(this), t || 0) }).promise() }) }, state: function() { return c }, always: function() { return e.done(arguments).fail(arguments), this }, then: function() { var a = arguments; return $.Deferred(function(c) { $.each(b, function(b, f) { var g = $.isFunction(a[b]) && a[b]; e[f[1]](function() { var a = g && g.apply(this, arguments); a && $.isFunction(a.promise) ? a.promise() .done(c.resolve) .fail(c.reject) .progress(c.notify) : c[f[0] + "With"](this === d ? c.promise() : this, g ? [a] : arguments) }) }), a = null }).promise() }, promise: function(a) { return null != a ? $.extend(a, d) : d } }, e = {}; return d.pipe = d.then, $.each(b, function(a, f) { var g = f[2], h = f[3]; d[f[1]] = g.add, h && g.add(function() { c = h }, b[1 ^ a][2].disable, b[2][2].lock), e[f[0]] = function() { return e[f[0] + "With"](this === e ? d : this, arguments), this }, e[f[0] + "With"] = g.fireWith }), d.promise(e), a && a.call(e, e), e } }(jQuery)); var p = { run: function() { return $() .promise() .then(function() { console.log("call together"); console.log("call together"); // do stuff // pass `data` to next `.then` return "call first"; }) .delay(2000) .then(function(data) { console.log(data); }) .delay(2000) .then(function() { console.log("call second"); }) } }; p.run(); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> </script> 
0
source

Here is my solution. I complete $.Deferred(afterBuild) and complete the original afterBuild , which in turn wraps the .promise(obj) method, extending the given obj using a custom delay method. What uses window.setTimeout :

Note: it only delays the done branch.

 function extendPromises(extensions) { $.Deferred = (function (originalDeferred) { return function (afterBuild) { var newAfterBuild = function (d) { d.promise = (function (originalPromise) { return function (obj) { return originalPromise.call(this, $.extend(obj, extensions)); }; })(d.promise); if (afterBuild) afterBuild.apply(this, arguments); return this; }; return originalDeferred.call(this, newAfterBuild); }; })($.Deferred); } extendPromises({ delay: function (delay) { return this.then(function (value) { var d = $.Deferred(); window.setTimeout(function () { d.resolve(value); }, delay); return d.promise(); }); } }); // so now I can do: $.when("hello") .then(function (value) { $("#log").append(value+"\n"); return value; }) .delay(1000) .then(function (value) { $("#log").append(value); return value; }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <textarea id="log" rows=5></textarea> 
0
source

All Articles