1

I'm trying to break a for-loop (labeled) from within a nested anonymous function, like this:

function ajax(iteration, callback) {
    var rtrn, xh;
    if (window.XMLHttpRequest) {
        xh = new XMLHttpRequest();
    } else {
        xh = new ActiveXObject("Microsoft.XMLHTTP");
    };
    xh.onreadystatechange = function() {
        if (xh.readyState == 4 && xh.status == 200) {
            callback(xh.responseText);
        };
    };
    xh.open("GET", "file.php?i=" + iteration, true);
    xh.send();
};

var atk_delay = 100;
loop:
for(i = 1; i <= 40; i++) {
    var to = atk_delay * i;
    setTimeout(
        function() {
            ajax(i, function(responseText) {
                var div = document.getElementById("combat");
                div.innerHTML += responseText;
                var arrRt = responseText.split("::");
                if(arrRt[0] == "stop") {
                    break loop;
                };
            });
        },
    to);
};

I really have no idea how to solve this. Obviously, the problem is that it cannot find the label. How can I resolve this?

Christian Lundahl
  • 2,000
  • 3
  • 18
  • 29
  • I've edited the question since the label had the wrong name. Now the code is as I have it. – Christian Lundahl Nov 22 '13 at 00:27
  • 4
    Are you aware that when you get to the point where you want to break it, the loop has already stopped? – kapa Nov 22 '13 at 00:30
  • `setTimeout` and `ajax` are obviously asynchronous, the logic inside the callback occurs after the loop has finished, and `i` gets lost due to the new scope. So there are two problems here, the ["Infamous JavaScript Loop Problem"](http://stackoverflow.com/questions/1451009/javascript-infamous-loop-problem) and the ["How to return the response from an AJAX call"](http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call) – elclanrs Nov 22 '13 at 00:35
  • ajax is asynchronous.... so loop might have made 4 more passes by the time you find your `stop` – charlietfl Nov 22 '13 at 00:36
  • 1
    Returning the responseText from my AJAX call works like a charm, but, no, I didn't realize that, @bažmegakapa. *sighs* Alright, I basically needs a complete new approach to this, I guess. – Christian Lundahl Nov 22 '13 at 00:37
  • @Perplexor Please describe what you want to happen, because it isn't obvious from the provided code. If it is what I think, you need another approach. – some Nov 22 '13 at 00:46
  • @some I want to do an AJAX call for every iteration of the for loop and if the responseText contains a stop word, it should break. Yes, I tried a different approach and it works like a charm! I'll post it as an answer. – Christian Lundahl Nov 22 '13 at 00:50

3 Answers3

1

So I solved it! Thanks for the help guys! You got me to realize I needed a completely different approach!

function ajax(callback) {
    var rtrn, xh;
    if (window.XMLHttpRequest) {
        xh = new XMLHttpRequest();
    } else {
        xh = new ActiveXObject("Microsoft.XMLHTTP");
    };
    xh.onreadystatechange = function() {
        if (xh.readyState == 4 && xh.status == 200) {
            callback(xh.responseText);
        };
    };
    xh.open("GET", "file.php", true);
    xh.send();
};

var atk_delay = 100;

function roll() {
    ajax(function(responseText) {
        var div = document.getElementById("combat");
        div.innerHTML += responseText;
        var arrRt = responseText.split("::");
        if(arrRt[0] == "cont") {
            setTimeout(roll, atk_delay);
        };
    });
};

setTimeout(roll, atk_delay);
kapa
  • 77,694
  • 21
  • 158
  • 175
Christian Lundahl
  • 2,000
  • 3
  • 18
  • 29
  • [Never pass a string to `setTimeout`](https://developer.mozilla.org/en/docs/Web/API/window.setTimeout#Passing_string_literals) - it's the same as calling `eval` on it, with all the problems it brings to the table. Always pass a function reference instead, like `setTimeout(roll, atk_delay);`. – kapa Nov 22 '13 at 11:32
  • Oh, I had no idea! Thanks! – Christian Lundahl Nov 22 '13 at 12:35
  • @kapa I see that the solution solves the problem by avoiding the problem. It's a good solution, but doesn't really match the question title. I have a different problem that has a similar question title but your solution doesn't really work for me. I know that you didn't do anything wrong; I'm just saying. – programmerRaj Jan 18 '20 at 00:29
0

Normally what you would do is have a variable that's accessible after each iteration of the loop that would indicate if you can break. This would be set in the anonymous function.

However, in your specific case, since you are calling setTimeout, execution of the loop might have been completed by the time you can even set the value. setTimeout schedules the function to later execution (in ms).

You can use a variable to exit the anonymous function early if something has flagged it as done.

Travis
  • 10,444
  • 2
  • 28
  • 48
0

A simple hack to debug anonymous blocks - call the debugger explicitly before the line you want to examine.

function foo().then(s => {
  ... some code
  debugger // here your code will break. 
  someVariableIwantToExamine
}
Elle
  • 117
  • 1
  • 4