Reputation: 341
I'm wondering if there is a better way to do an asynchronous loop in JavaScript? I've been using the following recursive method but I feel like there is probably a cleaner way. Any links / advice would be much appreciated. Thanks
var titles = ['Test 1', 'Test 2', 'Test 3'];
var i = 0;
addColumns();
function addColumns () {
if (i < titles.length) {
var data = {
'__metadata': { 'type': 'SP.FieldText' },
'FieldTypeKind': 3,
'Title': titles[i],
'MaxLength': '22'
};
postToSP.createColumns(baseURL, listName, data)
.then(function () {
i++;
addColumns();
})
.catch(function(e){
console.log('Error: ' + e);
})
} else {
return;
};
};
Upvotes: 2
Views: 99
Reputation: 2867
ES2017: You can wrap async code inside a function(say XHRPost) returning a promise( Async code inside the promise).
Then call the function(XHRPost) inside the for loop but with the magical Await keyword. :)
let http = new XMLHttpRequest();
let url = 'http://sumersin/forum.social.json';
function XHRpost(i) {
return new Promise(function(resolve) {
let params = 'id=nobot&%3Aoperation=social%3AcreateForumPost&subject=Demo1' + i + '&message=Here%20is%20the%20Demo&_charset_=UTF-8';
http.open('POST', url, true);
http.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
http.onreadystatechange = function() {
console.log("Done " + i + "<<<<>>>>>" + http.readyState);
if(http.readyState == 4){
console.log('SUCCESS :',i);
resolve();
}
}
http.send(params);
});
}
for (let i = 1; i < 5; i++) {
await XHRpost(i);
}
Upvotes: 0
Reputation: 21926
Assuming that the executions are value-independent (i.e. one does not depend on the value of the previous one) but sequential (they have to be round-trip completed in a deterministic order):
var allDone = titles.reduce((prev, title) => {
var data = {
'__metadata': { 'type': 'SP.FieldText' },
'FieldTypeKind': 3,
'Title': title,
'MaxLength': '22'
};
return prev.then(_ => postToSP.createColumns(baseURL, listName, data));
}, Promise.resolve(true));
This will queue up a series of ajax requests that will only kick off once the previous one completes. Error handling is left as an exercise to the reader. If the calls don't necessarily have to complete in a certain order, it's much cleaner this way:
let allDone = Promise.all(titles.map(title => postToSP.createColumns...));
Either way, now you've got a single Promise that will resolve when all the async calls complete.
Upvotes: 4