Mattias
Mattias

Reputation: 725

setTimeout not calling callback to interrupt while loop

I have a chess program that searches moves using a recursive alphaBeta algorithm (and some layers on top of that). I want to stop searching after 10 seconds (but I try with 1 second while making it work), so I use setTimeout to set a global flag.

  let timeOut = false;
  let i = 0;

  setTimeout(() => {
    timeOut = true;
    console.log('timeout');
    console.log('timeout');
    console.log('timeout');
    console.log('timeout');
  }, 1000);

  while (i < 1000 && timeOut === false) {
    score = mtdf(pos, i, score)
    console.log('depth:' + i + ', size: ' + tp.size());
    i++;
  }

This sure runs in the browser so I know the console.log statements should be printed in the browser but they aren't. The callback isn't called. Help please.

Edit: Added timeOut variable initialisation to make it more clear. Also, sorry, forgot to add i initialization (not that these declarations are even relevant to the question, since the problem is that setTimeout callback isn't even being executed...)

Upvotes: 1

Views: 675

Answers (3)

Eriks Klotins
Eriks Klotins

Reputation: 4180

Javascript is single threaded meaning that execution of "asynchronous" statements like setTimeout, setInterval, and XMLHttpRequest get queued on a single thread. If something blocks the thread (like your heavy while() loop) async statements get delayed.

See here for more elaborate answer

To make your code work, I suggest looking at the timestamp

var t0 = new Date().getTime(), t1 = t0;
while(true)
{
    // do stuff here
    t1 = new Date().getTime();
    if (t1 % 100 === 0) console.log(t1); // [debug ]print something every 100ms
    if (t1 - t0 > 1000) break; // kill the loop after one second

}

Upvotes: 1

Julian Paolo Dayag
Julian Paolo Dayag

Reputation: 3719

setTimeout is asynchronous meaning the program won't wait for the setTimeout to finish and the code will continue executing.

You need to use Promise to wait for the setTimout to finish so your code will behave properly.

Also, the problem of your code also lies in the variable declarations, you didn't declare the i and timeOut variables.

let timeOut = false;

new Promise((resolve) => {

  setTimeout(() => {
    timeOut = true;
    console.log('timeout');
    console.log('timeout');
    console.log('timeout');
    console.log('timeout');
    resolve();
  }, 1000);

}).then(() => {

  let i = 0;
  while (i < 1000 && timeOut === false) {
    score = mtdf(pos, i, score)
    console.log('depth:' + i + ', size: ' + tp.size());
    i++;
  }

});

Upvotes: -1

Quentin
Quentin

Reputation: 943230

setTimeout will run the function you pass to it:

  • After the specified time has passed
  • After the minimum time for a timeout has passed
  • When the event loop isn't busy doing something else

… whichever is the latest.

You can't use a timeout to interrupt your while loop. The JavaScript engine is too busy running the while loop to check to see if there are any functions waiting to run on the timeout queue.

Your function will be called after the loop has finished when the JS engine is no longer busy.


Don't try to interrupt your loop from the outside.

Before you enter the while loop, record the current time.

Each time you go around the loop, compare the current time with the recorded time.

If the difference is greater than the period you want to allow the loop to run from, exit the loop

Upvotes: 3

Related Questions