0

I have an array of XMLHttpRequest (working fine) and I want to know when they are all finished. I wrote the following array of on readystatechange functions:

xhr[i].open('post', 'PHP/write_and_exec_opt.php');
display_opt[i] = xhr[i].onreadystatechange = function(index) {
    if (xhr[index].readyState == 4 && xhr[index].status == 200) {
        text = xhr[index].responseText.trim();
        n_finished++;
        console.log('display_opt', n_finished);
    }
    xhr[index].send(data);
}(i);

The xhr requests are executed properly. But no output on the console log. Why not?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Laetis
  • 1,337
  • 3
  • 16
  • 28
  • It looks like you tried to use a [closure in the loop](http://stackoverflow.com/q/750486/1048572)? Have a look at [this](http://stackoverflow.com/a/25267864/1048572) – Bergi Sep 30 '16 at 14:01

2 Answers2

0

You're really close, but by executing your anonymous function, you end up assigning its return value to the onreadystatechange property. You never return a value, so you assign undefined. You probably meant to return a function:

xhr[i].open('post', 'PHP/write_and_exec_opt.php');
display_opt[i] = xhr[i].onreadystatechange = function(index) {
    return function() {
        if (xhr[index].readyState == 4 && xhr[index].status == 200) {
            text = xhr[index].responseText.trim();
            n_finished++;
            console.log('display_opt', n_finished);
        }
    };
}(i);
xhr[i].send(data);

That said, it gets confusing fast and there's no good reason to create the temporary function repeatedly, which is why I usually break things out:

Somewhere before (or after, but in any case in the same fundamental scope) your i loop:

function createStateChangeHandler(index) {
    return function() {
        if (xhr[index].readyState == 4 && xhr[index].status == 200) {
            text = xhr[index].responseText.trim();
            n_finished++;
            console.log('display_opt', n_finished);
        }
    };
}

Then in your i loop:

xhr[i].open('post', 'PHP/write_and_exec_opt.php');
display_opt[i] = xhr[i].onreadystatechange = createStateChangeHandler(i);
xhr[i].send(data);

For what it's worth, I'd suggest looking into using promises for this sort of thing, esp. now that they're a standard part of JavaScript (as of ES2015):

Promise.all(xhrArray.map(function(xhr) {
    return new Promise(function(resolve, reject) {
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if (xhr.status == 200) {
                    resolve(xhr.responseText.trim());
                } else {
                    reject(/*...include some error perhaps...*/);
                }
            }
        };
        xhr[index].send(data);
    });
})
.then(function(array) {
    // `array` contains an array o the results, in the same
    // order as `xhrArray`
})
.catch(function() {
    // At least one XHR failed
});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

You have 2 questions

  1. no, there is no builtin method to catch when you array of XMLHttpRequest finished. you need implement it by yourself

  2. you have no output because you don't assign function to onreadystatechange, you assign return value of execution of your function (undefined in your case).

Maxx
  • 1,740
  • 10
  • 17