Search code examples
javascriptxmlhttprequest

Javascript XMLHttpRequest in for loop


I know this question has been asked before, but I tried to apply the answers with no results.

I'm trying to do multiple requests on the same domain with a for loop but it's working only for the last record of my array. When I try with only one request it works fine. I don't understand.

Here is the code I use :

var xhr = new XMLHttpRequest();
var idArray = ['1', '2', '3', '4', '5'];

for(var i = 0;i < idArray.length;i++) {
    xhr.open('PUT', 'https://www.domain.com/url/' + idArray[i]);
    xhr.setRequestHeader('Authorization', authorizationToken);
    xhr.send(null);
    var test = setInterval(function () {
        if(xhr.readyState != 4) {
            //someCode
        } else {
            clearInterval(test);
        }
    }, 1000);
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4) {
            if(xhr.status != 200) {
                //someCode
            }
        }
    }
}

I've also tried this but still no results:

var xhr = new XMLHttpRequest();
var idArray = ['1', '2', '3', '4', '5'];

for(var i = 0;i < idArray.length;i++) {
    (function(i) {
        xhr.open('PUT', 'https://www.domain.com/url/' + idArray[i]);
        xhr.setRequestHeader('Authorization', authorizationToken);
        xhr.send(null);
        var test = setInterval(function () {
            if(xhr.readyState != 4) {
                //someCode
            } else {
                clearInterval(test);
            }
        }, 1000);
        xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                if(xhr.status != 200) {
                    //someCode
                }
            }
        }
    })(i);
}

I'm not seeing what I'm doing wrong.


Solution

  • Your second attempt is fairly close, but you need to create a separate XMLHttpRequest object for each request, within the inline-invoked function expression, see the relocated line with the *** comment:

    var idArray = ['1', '2', '3', '4', '5'];
    
    for(var i = 0;i < idArray.length;i++) {
        (function(i) {
            var xhr = new XMLHttpRequest(); // ***
            xhr.open('PUT', 'https://www.example.com/url/' + idArray[i]);
            xhr.setRequestHeader('Authorization', authorizationToken);
            xhr.send(null);
            var test = setInterval(function () {
                if(xhr.readyState != 4) {
                    //someCode
                } else {
                    clearInterval(test);
                }
            }, 1000);
            xhr.onreadystatechange = function () {
                if (xhr.readyState == 4) {
                    if(xhr.status != 200) {
                        //someCode
                    }
                }
            }
        })(i);
    }
    

    Technically, since you don't use i anywhere in the callbacks you're creating in there, you don't need to pass i in and take it as a parameter to the IIFE (but with that ES5-level syntax, you do need the IIFE so that you have separate xhrs).

    In ES2015+, there's no need for the IIFE anymore, just use let and const:

    const idArray = ["1", "2", "3", "4", "5"];
    
    for (const id of idArray) {
        const xhr = new XMLHttpRequest();
        xhr.open("PUT", "https://www.example.com/url/" + id);
        xhr.setRequestHeader("Authorization", authorizationToken);
        xhr.send(null);
        const test = setInterval(() => {
            if (xhr.readyState !== 4) {
                //someCode
            } else {
                clearInterval(test);
            }
        }, 1000);
        xhr.onreadystatechange = () => {
            if (xhr.readyState == 4) {
                if (xhr.status !== 200) {
                    //someCode
                }
            }
        };
    }
    

    These days I'd probably use fetch instead of XHR as well.


    Side note: Not sure what the interval timer is for there, so I've left it, but your onreadystatechange handler will get called, no need to back it up with a timer.