I'm new to deferred classes in JavaScript and would like to implement a function which will loop through forms and submit them one by one.
Looks like Deferred classes are the way to accomplish this.
I tried following this answer, but for some reason my implementation starts, waits 3 seconds and completes. I want it to show a different form name every 3 seconds until it's done with all the forms then complete.
What am I doing wrong? JSFIDDLE
function syncAll() {
var promises = [];
var forms = [
{'name':'form 1'},
{'name':'form 2'},
{'name':'form 3'},
{'name':'form 4'}];
$.each(forms, function (index, value) {
var def = new $.Deferred();
setTimeout(function () {
$("#output").html("Syncing: " + value.name);
def.resolve({ 'message': 'finito!' });
}, 3000);
promises.push(def);
});
return $.when.apply(undefined, promises).promise();
}
$.when(syncAll()).done(function(response){
$("#output").html(response.message);
});
/*
syncAll().done(function (response) {
$("#output").html(response.message);
}));
*/
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output">Start</div>
JSFiddle: https://jsfiddle.net/TrueBlueAussie/v6cgak1u/2/
This uses a promise = promise.then(functionReturningNextPromise)
pattern:
function syncAll() {
var promise = $.when(); // Start with a resolved promise.
var forms = [
{'name':'form 1'},
{'name':'form 2'},
{'name':'form 3'},
{'name':'form 4'}];
$.each(forms, function (index, value) {
promise = promise.then(function(){
var def = $.Deferred();
setTimeout(function () {
$("#output").html("Syncing: " + value.name);
def.resolve({ 'message': 'finito!' });
}, 3000);
return def.promise();
});
});
return promise;
}
$.when(syncAll()).done(function(response){
$("#output").html(response.message);
});
This could be improved a bit by replacing the setTimeout and having a timed promise method instead that also chains together (still implemented using setTimeout).
Note that new
is not required on $.Deferred()
EDIT :
Features of javascript and jQuery can be exploited to make the code slightly more concise :
function syncAll() {
var forms = [
{'name':'form 1'},
{'name':'form 2'},
{'name':'form 3'},
{'name':'form 4'}
];
return forms.reduce(function(promise, value) {
return promise.then(function() {
return $("#output").delay(1000).html("Syncing: " + value.name).promise();
});
}, $.when()).then(function() {
return {'message': 'finito!'};
});
}
syncAll().then(function(response) {
$("#output").html(response.message);
});
This is essentially the same paradigm as above but exploits :
forms
array..delay()
instead of setTimeout()
, to implement delay.