2

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;
    };
};
3
  • 1
    Why do the calls need to execute in sequence? Is order that important? Commented Jul 12, 2017 at 12:59
  • They don't need to be in sequence, but ShrePoint throws an error when trying to write all 3 concurrently Commented Jul 12, 2017 at 13:14
  • 1
    Ah ok. Then definitely use the first pattern in my answer as the next call won't be fired off until the previous one round-trips. Second tries to do them all concurrently. Commented Jul 12, 2017 at 13:15

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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);
   }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.