• 0

[JavaScript] For Loop Cycling Through an Array


Question

I'm making a Minecraft server list for fun and for experience. When I try to run this code, it only displays that us.mineplex.com is up, and it is random. Sometimes it shows that 7 times, and sometimes 4.

 

JavaScript

        var servers = ["therealms.us", "craftboss.net", "us.mineplex.com"];
        for(var i=0;i<servers.length;i++){
            var ip = servers[i];
            var xhr = new XMLHttpRequest();
            xhr.open("GET", 'http://minecraft-api.com/v1/get/?server=' + ip, true);
            xhr.onreadystatechange = function() {
                    if (xhr.readyState === 4) {
                            data = JSON.parse(xhr.responseText);
                            if (data.status) {
                                    $("#server-status").append('<div class="alert alert-success">' + ip + ' is online!');
                            } else {
                                    $("#server-status").append('<div class="alert alert-danger">' + ip + ' is down!</div>');
                            }
                    }
            };
            xhr.send();
        }

HTML

      <div class="container">
          <div id="server-status"></div>
       </div>
    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
    <script src="https://code.jquery.com/jquery-migrate-1.2.1.min.js"></script>

Here is the documentation: http://minecraft-api.com/documentation#info

Link to comment
Share on other sites

8 answers to this question

Recommended Posts

  • 0

Your problem probably stems from the fact that you're reusing your "xhr" object within the loop. In JavaScript, the only structure that creates scope is a function. If statements, loops, and other "block" structures do not create new scope. My guess would be that you're overwriting the "xhr" object each time your loop iterates, causing you to lose the callback for the previous GET request.

 

Since you're using jQuery already, I would suggest using its provided "$.Get" method. If you want to stick with custom "xhr" logic, you can extract that logic from the loop into it's own function. That should create the necessary scope that you're looking for.

        $(function() {
            var servers = ["therealms.us", "craftboss.net", "us.mineplex.com"];
            for (var i = 0; i < servers.length; i++) {
                var ip = servers[i];
                Get(ip);
            }

            function Get(ip) {
                var xhr = new XMLHttpRequest();
                xhr.open("GET", "/Home/Test?server=" + ip, true);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        data = xhr.responseText;
                        if (data) {
                            $("#server-status").append("<div>" + data + "</div>");
                        }
                        else {
                            $("#server-status").append("<div>no data</div>");
                        }
                    }
                };
                xhr.send();
            }
        });

edit: also, if you haven't already; you should put your logic in jQuery's document ready function so that you make sure the DOM is loaded before you add to it. (I also fiddled with your logic a bit to fit my test, make sure you don't copy it exactly.)

  • Like 3
Link to comment
Share on other sites

  • 0

Have you validated that the Minecraft API is returning the other servers being up as well?

 

 

 

Does this work?

for(var i=0;i<servers.length-1;i++){

 

 

That would chop off the last element in the list.  You only need to subtract one if you're doing a "<=" comparison.

Link to comment
Share on other sites

  • 0

Your problem probably stems from the fact that you're reusing your "xhr" object within the loop. In JavaScript, the only structure that creates scope is a function. If statements, loops, and other "block" structures do not create new scope. My guess would be that you're overwriting the "xhr" object each time your loop iterates, causing you to lose the callback for the previous GET request.

 

Since you're using jQuery already, I would suggest using its provided "$.Get" method. If you want to stick with custom "xhr" logic, you can extract that logic from the loop into it's own function. That should create the necessary scope that you're looking for.

        $(function() {
            var servers = ["therealms.us", "craftboss.net", "us.mineplex.com"];
            for (var i = 0; i < servers.length; i++) {
                var ip = servers[i];
                Get(ip);
            }

            function Get(ip) {
                var xhr = new XMLHttpRequest();
                xhr.open("GET", "/Home/Test?server=" + ip, true);
                xhr.onreadystatechange = function () {
                    if (xhr.readyState === 4) {
                        data = xhr.responseText;
                        if (data) {
                            $("#server-status").append("<div>" + data + "</div>");
                        }
                        else {
                            $("#server-status").append("<div>no data</div>");
                        }
                    }
                };
                xhr.send();
            }
        });

edit: also, if you haven't already; you should put your logic in jQuery's document ready function so that you make sure the DOM is loaded before you add to it. (I also fiddled with your logic a bit to fit my test, make sure you don't copy it exactly.)

Yeah, I was thinking that it was something like that. I'll recode it to be somewhat like your logic, and I'll see if it works.

Link to comment
Share on other sites

  • 0

Your problem probably stems from the fact that you're reusing your "xhr" object within the loop. In JavaScript, the only structure that creates scope is a function. If statements, loops, and other "block" structures do not create new scope. My guess would be that you're overwriting the "xhr" object each time your loop iterates, causing you to lose the callback for the previous GET request.

 

Really!?  That's rather counter-intuitive.  Suddenly I feel less bad that the Mozilla CEO, creator of JS, quit if he designed it to work like that. :P

Link to comment
Share on other sites

  • 0

Really!?  That's rather counter-intuitive.  Suddenly I feel less bad that the Mozilla CEO, creator of JS, quit if he designed it to work like that. :p

Yeah, it's definitely odd coming from a more structured language like C++ or C#. But it's also a reason why functional languages are great. They are incredibly flexible and expressive once you understand the quirks.  :)

 

It works. :)

Glad to hear it.

Link to comment
Share on other sites

  • 0

Yeah, it's definitely odd coming from a more structured language like C++ or C#. But it's also a reason why functional languages are great. They are incredibly flexible and expressive once you understand the quirks.  :)

I'd say it's more a failure of JavaScript's crappy variable scoping rules than anything. Functional languages are great, but JavaScripts variable scope rules are most certainly not.

  • Like 1
Link to comment
Share on other sites

This topic is now closed to further replies.