-1

I have a small JavaScript code in which I'm trying to use setTimeout to either wait for some external input to arrive (via responseReceived variable), OR wait for a max threshold time and then quit.

Here's the code:

var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;

alert("Alert1");

while(keepWaiting == true) {
  setTimeout(function() {
    totalTimeWaited = totalTimeWaited + waitInterval;
    alert("Alert2");
    if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
      keepWaiting = false;
    }
  }, waitInterval);
}

The problem is for some reason setTimeout(..) never actually calls the anonymous function created inside it. I checked this by placing breakpoints in Chrome's JavaScript execution control, and execution never actually stops at any breakpoint placed inside the anonymous function. JavaScript's execution keeps toggling between the while .. line and setTimout(..) line. responseReceived is set elsewhere in the code. Another way of saying this is that the first alert shows (Alert1) but the second one never shows (Alert2).

What am I doing wrong ?

EDIT:

I went through the 'duplicate' question reported but I fail to see how that is relevant to my question. My question is not regarding the while loop. Rather it's about why the internal anonymous function isn't being called.

Ahmad
  • 12,886
  • 30
  • 93
  • 146
  • 2
    Possible duplicate of [Javascript - wait until flag=true](http://stackoverflow.com/questions/22125865/javascript-wait-until-flag-true) – Alexander O'Mara Aug 16 '16 at 17:47
  • I'm not sure how that question is connected to the one I'm asking. I know JavaScript is single-threaded. The problem isn't with the `while` loop. The problem is that the internal anonymous function isn't called for some reason. – Ahmad Aug 16 '16 at 17:59
  • 2
    That's because you `while` loop never ends, so your timer never gets a chance (single threaded). – Alexander O'Mara Aug 16 '16 at 18:00
  • I still don't understand your point. When I'm inside the while loop, the setTimeout function should wait for 500 ms, then fire the anonymous function, and then re-evaluation whether the while loop should continue or not. This is all single-threaded stuff so I don't see your point. `setTimeout` is blocking from what I know, so `while` evaluation can only be done after `setTimeout` is finished. – Ahmad Aug 16 '16 at 18:03
  • While loop should end eventually according to the logic inside the `setTimeout` anonymous function, even if `responseReceived` never actually becomes true. – Ahmad Aug 16 '16 at 18:05
  • 2
    `setTimeout` is not blocking, and does not wait for the callback to be called before returning. – Alexander O'Mara Aug 16 '16 at 18:05
  • Ah, I didn't know that. Thanks for pointing that out. Wondering what the solution to this problem is now. – Ahmad Aug 16 '16 at 18:10

2 Answers2

1

Your code killed my browser tab. :D

Why don’t you just use setInterval and get rid of the while loop?

var MAX_WAIT_THRESHOLD = 5000;
var waitInterval = 500;
var totalTimeWaited = 0;
var waiting = true;

alert("Alert1");

var interval = setInterval(function() {
    totalTimeWaited += waitInterval;
  alert("Alert2");
  if (responseReceived || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
    // stop waiting
    clearInterval(interval);
    waiting = false;
    alert("Done");
  }
}, waitInterval);
Oliver
  • 507
  • 6
  • 12
0

This issue is related with the javascript concurrency model.

As far as I know, all your setTimeout callbacks can only be executed after the while loop ends, because that while loop is a message blocking the queue. But in this case, it never ends.There was another SO thread explaining this, but I can't find it now.

I see you're actually controlling the max time of the loop with control variables. However, since this control code is inside a setTimeout callback, it will not be pushed into the queue until the loops end, so the control var keepWaiting will never turn to false inside the loop. Should you take that control code outside the setTimeout function, it wouldn't break the browser and will at some point show the 'alert2' message -several times, in fact-:

var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;
var responseReceived = false;

console.log("Alert1");

while(keepWaiting == true) {
 setTimeout(function() {

console.log("Alert2");

}, waitInterval);

   totalTimeWaited = totalTimeWaited + waitInterval;
   if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
  keepWaiting = false;
    }   
}

However, all the callbacks will fire at the end for the reasons exposed before.

If you want an eternal loop of setTimeouts, use recursion instead of iteration.

Sergeon
  • 6,638
  • 2
  • 23
  • 43