1

I'm having a problem that I can't solve. I have a loop in javascript where the condition variable to stop depends on a global variable. The loop starts looping and when I change the value of that global variable it never stops.

stop = false;
var i = 0;
while ((stop == false) && (i<100000)){
    console.log("hi-"+i);
    i++;
}

While loop is running, if I do stop = true, it never stops. I do not know why is that.

Any idea?

Thanks!

8
  • Your code doesn't change stop inside the loop Commented Oct 10, 2014 at 14:03
  • JavaScript is single threaded. Your event handler (i suppose) that sets stop to true gets executed only after the while loop is done. Commented Oct 10, 2014 at 14:03
  • @hindmost I change the value of stop outside the loop... Commented Oct 10, 2014 at 14:18
  • @user2422900 So this is the problem. It should be changed inside the loop, otherwise it will have no effect Commented Oct 10, 2014 at 14:20
  • Thanks... And which is the way I can do so? @techfoobar Commented Oct 10, 2014 at 14:21

3 Answers 3

2

JavaScript is inherently single threaded. Once a block of code has started running, it will run to completion before anything else happens. IE the event where you're setting stop to true will not execute until after the while loop has finished.

You need to split your loop into sections and run each section individually, allowing other events to take place:

stop = false;
var i = 0;

function loopLogic() {
  var tempStop = i + 500;
  while (i < tempStop) {
    //original processing logic
    console.log("hi-" + i);
    i++;
  }

  if (!stop && i < 100000)
    window.setTimeout(loopLogic, 0);

}
window.setTimeout(loopLogic, 0);

This breaks up the function into multiple chunks of 500 at a time. The setTimeout of 0 duration lets the function continue (almost) immediately, but will put the next chunk at the bottom of the execution chain. This allows other events to happen and therefore will allow updating of stop to true

Here's a fiddle showing this approach.

The other approach available in compliant browsers is the Web Worker, but that's starting to get beyond the scope of this question.

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

2 Comments

And which is the way I can do so? Imagine that idk, I want the while to be stopped when I do a click en the body... How could I implement a thing like that?
Hey, I have noticed that if instead of having the line of console.log("hi-"+i); I have a call to a function, it does not work...
0

You can try using the setInterval.... Put what you need to do into a function and call it at some interval... Take a look here...

http://jsfiddle.net/o5mnb7jv/1/

var stop = false;
var obj = document.getElementById("btn").addEventListener("click", function(){
    stop = true;
});
var interval;
function loop(){
    var result = document.getElementById("result");
    if(!stop){
        result.innerHTML = "Running...";
    }else{
        clearInterval(interval);
        result.innerHTML = "Stopped...";
    }
}
interval = setInterval(loop, 500);

2 Comments

Hmmm... but I need that the function executes a finite quantity of times. Using setInterval will execute infinitely until stop changes.
You can stored the instance of the interval and use clearInterval to stop it....
0

It sounds like you were expecting JS to be multithreaded, but it is not, which makes certain things awesome. For example, if JS were multithreaded, what would the following do?

if (x === 3) {
    alert(x);
}

The answer in JS is "it alerts 3," but if JS were multithreaded, there would be nothing stopping another thread from editing x between the if and the alert, so it wouldn't be well-defined.

You can return control to the browser's event loop while making sure that some code will run, by scheduling that function, either with setTimeout or setInterval. This also lets you do recursion without a massive call stack, if you're willing for the result of that recursion to be asynchronous. Furthermore JS is getting a new feature (generators and the yield keyword) which will make it easier to "pause" a function somewhere in the middle only to resume it later.

The simplest way to do what you're trying to do is:

var i = 0, running = true;
function iter() {
    if (running && i < 100000) {
        console.log("hi", i++);
        setTimeout(iter, 0);
    }
}
iter();

You can also use a non-zero time in the setTimeout call -- e.g. the human reaction time is something like 200ms so if you just need it to seem continuous from a human perspective, change the 0 to 100; it'll give your computer a little more space to breathe.

You can also use setInterval but just be aware that if some CPU-intensive function blocks other execution for a while, you'll queue up a bunch of the same function that all want to execute one after another. When a setTimeout thread calls setTimeout, there is a minimum delay which is enforced by setTimeout; this is not the case with setInterval (which claims instead that the average time between calls is consistent, but makes no claims about the minimum or maximum delays between them).

For the sake of setInterval you will probably want to stop the interval after some point. Adding the if check on i of course makes the function an empty function which does nothing, so it doesn't waste much time, but if you want to unschedule it, capture the result of setInterval and pass it to clearInterval.

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.