Reputation: 217
I have an array
of statements and I want to loop through each and submit to the server
via an ajax
call. I have to make sure each ajax
request is executed before the next request is sent, because on the server
side code, I am creating a unique key
for this array
of statements. What happens is before I can commit the first request, the second request comes in and I end up have 2 separate keys being created since it sees each of them as a first time request. I can't rely on timeout entirely and the code I have so far, continues with the loop.
function formPostSubmission(form){
var parts = ['a', 'b', 'c'];
var i = 0;
parts.forEach(function(entry) {
i++;
datafield ={
answer:entry,
displayOrder:i,
ajaxName:'statementPartialSubmit'
};
$.when(submitAjaxData(form, datafield)).then(function succesHandler(data){
console.log("promise test "+data);
console.log("Below request ");
},
function errorHandler(){
console.log("Error occurred ");
})
console.log("Go for next ");
});
}
function submitAjaxData(form, datafield) {
console.log(" called submitAjaxData ");
var loadurl = domainName + "/ajax-call-handler";
return $.ajax({
url: loadurl,
method: "GET",
data: datafield
});
}
I was hoping to check response data for a success and then proceed within the loop. But this is how my console
prints.
called submitAjaxData
Go for next
called submitAjaxData
Go for next
promise test
Below request
promise test
Below request
Upvotes: 3
Views: 6512
Reputation: 2772
I wrote this function, PromiseAllSeq, to execute an array of promises sequentially.
You can pass a callback as the second parameter if you choose, but given your issue i've put together a working demo based on your code.
console.clear();
/**
* Promises will wait for each other and will return any[].
* If a promise is rejected it will stop.
* @param arr - (Promise<any> | ()=>Promise<any>)[] - Accepts promise or a function that returns a promise
* @param callback(response, index) - If callback 'returns' it will overwrite the current response. Useful for changing the response.
* @returns any[]
*/
const PromiseAllSeq = (arr, callback) => {
let result = [];
if (typeof callback !== 'function') {
callback = () => {};
}
const rec = (arr) => {
return new Promise((resolve, reject) => {
if (arr.length) {
(typeof arr[0] === 'function' ? arr[0]() : arr[0]).then(res => {
let cb = callback(res, result.length);
result = result.concat(typeof cb !== 'undefined' ? cb : res);
arr.splice(0, 1);
resolve(arr.length ? rec(arr) : result);
}).catch(err => {
reject(err);
})
} else {
resolve(result);
}
})
}
return rec(arr);
}
function succesHandler(data, index) {
// Here i can alter 'data'
data['finishedPromiseNr'] = index;
console.log("promise test ", data, index);
console.log("Go for next ");
return data;
}
function errorHandler(err) {
console.log("Error occurred ", err);
}
function submitAjaxData(form, datafield) {
console.log("called submitAjaxData ", datafield);
//var loadurl = domainName + "/ajax-call-handler";
// Mock some requests with delayed responses
// https://reqres.in/#console
var loadurl = "https://reqres.in/api/users?delay=" + datafield.fakeDelay;
return $.ajax({
url: loadurl,
method: "GET",
data: datafield
});
}
function formPostSubmission(form) {
var parts = ['a', 'b', 'c'];
var i = 0;
let poll = [];
parts.forEach(function(entry) {
i++;
// 'datafield' was not assigned with var or let
// Reassigning it on each loop will allow 'datafield' to pass in the anonymous function below
let datafield = {
answer: entry,
displayOrder: i,
ajaxName: 'statementPartialSubmit',
fakeDelay: parts.length - i
};
// Wrong: submitAjaxData is called, that means, the requests are sent immediately.
// poll.push( $.when(submitAjaxData(form, datafield) );
// Correct: Wrap and return $.when into a function otherwise 'submitAjaxData' will trigger the requests
poll.push(() => $.when(submitAjaxData(form, datafield)));
});
PromiseAllSeq(poll, succesHandler).then(responseList => {
console.log('final response');
console.log(responseList);
}).catch(errorHandler)
}
formPostSubmission(null);
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
Upvotes: 0
Reputation: 226
you could use this solution by using await
, for example :
for (let f of files) {
await $.ajax({/* your ajax config*/ });
}
Upvotes: 2
Reputation: 226
use promises :
var promises = [];
for (var i = 0; i < $total_files; i++) {
// jQuery returns a prom
promises.push($.ajax({
/* your ajax config*/
}))
}
Promise.all(promises)
.then(responseList => {
console.dir(responseList)
})
Upvotes: 3