This question is carefully distilled version of not asynchronous function executed as jQuery Deferred.
We have 2 jsfiddles:
http://jsfiddle.net/XSDVX/1/ - here the progress event is not fired, despite calling notify() function.
http://jsfiddle.net/UXSbw/1/ - here the progress event is fired as expected.
The only difference is one line of code:
setTimeout(dfd.resolve,1);
versus
dfd.resolve();
Questions are:
How is .then catching the .notify that is called before this callback returns when we delay the resolve? Think about it. .then takes the deferred object that was returned from it's first parameter and creates a new deferred object from it, binding to it's done progress and fail events. If the notify was called before the deferred was returned, how is .then catching it even with a setTimeout? (Thanks to https://stackoverflow.com/users/400654/kevin-b for asking this)
Can I get rid of setTimeout()
and still have progress callback fired?
Made a big refactor and here is one final working example, with progress monitoring.
Now the important parts.
EDIT: I forgot your first question. This behavior is achieved via the means of a closure (the dfd variable in the "x" function).
The function "x" returns immediately (after triggering a notify event which now can be processed, as all the Deferreds of the execution chain have been created, and the done, fail, progress hooks of the "executePromiseQueueSync" have been hooked).
Also the function of the setTimeout "closes" the dfd in a closure, so it can access the variable despite that the "x" has returned. The "then" call continues by creating the next deferred that is linked to the first one.
After the JS VM yields (it has not other things to do), the setTimeout triggers it's associated function, that (by the means of closure) have access to the "closed" dfd variable. The Deferred is resolved and the chain can continue.
EDIT2: Here is a refactored version that adds support for long executing, deferred supported functions, where they notify their caller for their progress.
EDIT3: Here is another version, without underscore binding and with a jq-ui progressbar example.
By the way this is very good idea for complex app initialization routines.
Source (of the first version)
function executePromiseQueueSync(queue, beacon){
var seed = $.Deferred(),
le = queue.length,
last;
beacon.notify(0);
last = _.reduce(queue, function(memo, ent, ind){
var df = $.Deferred();
df.then(function(){
console.log("DBG proggie");
beacon.notify((ind+1)/le*100);
});
console.log("DBG hook funk "+ind);
memo.then(function(){
console.log("DBG exec func "+ind);
ent.funct.apply(null, ent.argmnt);
df.resolve();
});
return df.promise();
}, seed.promise());
last.then(function(){
beacon.resolve(100)
});
seed.resolve(); // trigger
return beacon.promise();
}
function x(){
// do stuff
console.log("blah");
}
var promisesQueue = [],
beacon = $.Deferred();
promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});
promisesQueue.push({funct: x, argmnt:[]});
function monTheProg(pct)
{
console.log('progress '+pct);
}
// first hook, then exec
beacon.then(function(){
console.log('success');
}, function(){
console.log('failure');
}, monTheProg);
// do the dance
executePromiseQueueSync(promisesQueue, beacon)
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