How can I dynamically add pending to a promise from this jsFiddle?

Regarding this jsFiddle , I am trying to dynamically add the โ€œpendingโ€ ones that are created when the event fires, so the callback is executed when all the pending ones are resolved, including those that were added later:

Relevant Code:

var promises = [ deferred1, ... ]; var p = when.all(promises).then(function() { console.log('All done!!'); //! trigger }); promises.push( deferredFromEvent ); // << ignored 

update: suggestions using Q or jQuery are welcome, I'm looking for one that works

+6
source share
4 answers

Treat your fixed promises as a separate package rather than dynamic (s).

Wait for promises in the bundle, and then pipe their common result through $.when() in the initially empty array. You can dynamically inject new promises into this array at any time.

http://jsfiddle.net/atesgoral/YVkVa/1/

HTML:

 <p>You have 5 seconds to inject!</p> <button id="inject">Inject Deferred 3</button> <button id="resolve">Resolve Deferred 3</button> <p>Deferred 1: <span id="dfd1">pending<span></p> <p>Deferred 2: <span id="dfd2">pending<span></p> <p>Deferred 3: <span id="dfd3">pending<span></p> <h1 id="result"></h1> 

JavaScript:

 var dfd1 = $.Deferred(), dfd2 = $.Deferred(), fixed = [ dfd1.promise(), dfd2.promise() ], multiplexed = $.when.apply($, fixed), // Bundle the fixed ones reservoir = []; // Reservoir for dynamic promises // The solution to your problem lies here. The rest is scaffolding. var ultimate = multiplexed.pipe(function () { return $.when.apply($, reservoir); }); ultimate.done(function() { $("#result").text("Done!"); }); window.setTimeout(function () { dfd1.resolve(); $("#dfd1").text("resolved"); }, 2500); window.setTimeout(function () { dfd2.resolve(); $("#dfd2").text("resolved"); }, 5000); var dfd3 = $.Deferred(); $("#inject").click(function () { reservoir.push(dfd3.promise()); }); $("#resolve").click(function () { dfd3.resolve(); $("#dfd3").text("resolved"); }); 
+1
source

Create all your promises that you know you need. Create .when with it. Keep the promise returned with .when . When you add new events that require new promises, add new .when s, using the promise of previous .when s, as well as all new promises that you have completed.

Your application will have several single points of failure if you use the final .when as your "Go ahead with the application." IE: if any promise fails at any moment, then any .when created after that .when also fail.

... but if it is your intention or you have a clear error handling, it should do you.

I'm trying to preserve this agnostic library - usually, I use my own implementation, which is halfway between something that jQuery does and something that Crockford did in a recent conversation, but if we assume that:

functions return promise handlers
"when" returns the promise handler, the monkey handlers have at least .done and .fail - either accepting two arguments or something else and everything that happens inside the function will determine whether the promise is rejected/resolved or kept/broken ( or something else), then you can get a bunch of functionality that looks like this:

 var doing = doSomething(), // returns promise making = makeSomething(), // returns promise loading = loadSomething(), // returns promise dependencies_lvl_1 = when(doing, making, loading); 

You can add a new module or widget later - perhaps this will save some work:

 var saving = saveSomething(), //returns promise dependencies_lvl_2 = when(dependencies_lvl_1, saving); 

You may need to switch pages after this, but you need your cache data first

 var caching = cacheData(), // returns promise when(dependencies_lvl_2, caching) .done(goToNextPage) .fail(handleError); 

If you look at this, you know that as long as when returns a promise that is successful only when all promises are saved (and when all promises are saved) and none of them break, then dependencies_lvl_2 there includes all the dependencies dependencies_lvl_1 , plus additional promises.

Level-3 .when , therefore, has permission depending on each thing that has been added to the chain.

And while you continue to cache your promises into variables (or some future access), you can continue to bind them together, for eternity.

0
source

"... therefore, the executed callback is called only when all pending are allowed, including those added later" does not make sense, however I think I know what you mean.

If I understood correctly, then you want to be able to call "re-firable when ()" - something like this (based on jQuery):

 function PromiseSet(memory, once) {//javascript Constructor var flags = []; if(memory) flags.push('memory'); if(once) flags.push('once'); var promises = [], doneCallbacks = $.Callbacks(flags.join(' ')), failCallbacks = $.Callbacks(flags.join(' ')); this.add = function(promise, val) { promises.push(promise); if(val) { this.fire(val); } return this; }; this.done = function(fn) { doneCallbacks.add(fn); return this; }; this.fail = function(fn) { failCallbacks.add(fn); return this; }; this.fire = function(val) { val = val || null; $.when.apply($, promises).then( function() { doneCallbacks.fire(val); }, function() { failCallbacks.fire(val); } ); return this; }; return this; } 

untested

All methods return this to make them whole.

If I wrote the constructor correctly, you can control its detailed behavior by passing booleans to new PromiseSet() . For your use, I think you need to go through (true, false) , but try other settings to see what happens.

Sequence example:

 var myPromiseSet = new PromiseSet(true, false); myPromiseSet.add(promise1); myPromiseSet.add(promise2).add(promise3); myPromiseSet.done(myDoneFunction).fail(myFailFunction); myPromiseSet.fire("foo"); myPromiseSet.add(promise4).fire(); 
0
source

Take a look at this solution. Thanks to this implementation, you can track a lot of added dynamic promises. If you are using jQuery Deferred, you can do it. jsFiddle

Notice that I used _. each method is from the lodash library, so you will also need to install lodash

 function doAlotOfAsyncThings(callback) { var promises = []; var def = $.Deferred(); console.log('Adding first promise'); promises.push(def.promise()); setTimeout(function() { // Dinamically adding second promise. Important note: last added promise must be added to array BEFORE previous promise has been resolved var def2 = $.Deferred(); var def3 = $.Deferred(); console.log('Dinamically adding second and third promises'); promises.push(def2.promise()); promises.push(def3.promise()); console.log('Resolving first promise'); def.resolve(); setTimeout(function() { console.log('Resolving second and third promises'); def2.resolve(); def3.resolve(); }, 1500); }, 1000); function checkAllDone() { console.log('Checking $.when'); $.when.apply(null, promises).then(function() { // we have to check state of every promise in array var all_resolved = _.every(promises, function(elem) { return elem.state() == 'resolved'; }); if(all_resolved) { console.log('All promises are resolved! callback();') callback(); } else { console.log('Hm, seems that some promises were dinamically added, waiting for them..'); checkAllDone(); } }); } checkAllDone(); } doAlotOfAsyncThings(function(){ console.log('Done'); }); 

With Q.js, this is even shorter.
In this solution, I use _. Any method from the lodash library

 function doAlotOfAsyncThings(callback) { var promises = []; var def = Q.defer(); console.log('Adding first promise'); promises.push(def.promise); setTimeout(function() { // Dinamically adding second promise. Important note: last added promise must be added to array BEFORE previous promise has been resolved var def2 = Q.defer(); var def3 = Q.defer(); console.log('Dinamically adding second and third promises'); promises.push(def2.promise); promises.push(def3.promise); console.log('Resolving first promise'); def.resolve(); setTimeout(function() { console.log('Resolving second and third promises'); def2.resolve(); def3.resolve(); }, 1500); }, 1000); function checkAllDone() { console.log('Checking $.when'); Q.all(promises).then(function() { // Q remove resolved promises from array so we have to check if array contains some non-undefined elements (those elements would be non-resolved dinamically added promises) if(_.any(promises)) { console.log('Hm, seems that some promises were dinamically added, waiting for them..'); checkAllDone(); } else { console.log('All promises are resolved! callback();') callback(); } }); } checkAllDone(); } doAlotOfAsyncThings(function(){ console.log('Done'); }); 
0
source

All Articles