UPDATE
Solved, sort of. The problem is the single-threaded nature of Javascript and my misunderstanding of its event model. The loop doesn't get interrupted by the timeout.
So, the solution is that instead of using a callback, I just grab a timestamp before starting the loop, and then each time through the loop compare against it. If more than X seconds have passed, I fire the confirm dialog:
let start = new Date();
...
while ( keepGoing && matchNotFound )
{
...
let end = new Date();
if ( end - start > 10000 )
{
keepGoing = confirm( "This run seems to be taking a while - keep going?" );
start = end;
}
}
Probably not the most efficient or idiomatic solution, but it works for my purposes.
ORIGINAL
I'm trying to call a function through setTimeout, but the callback never fires no matter what time interval I use. I don't know if the problem is in how I've set up the call, or if my understanding of how to use it is completely wrong.
I'm in the early stages of teaching myself Javascript, and have written a version of Dawkins' Weasel program as an exercise. Depending on the parameters the algorithm can take a long time to run, so my thought was to use setTimeout to call a function asking the user if they want to continue and give them the option to bail, sort of like so:
var keepGoing = true; // flag to continue main loop
var timeoutId; // stores result of setTimeout
...
/**
* Asks the user if they want to continue. If they do, reschedule this function to
* execute again after 5 seconds.
*/
function alertFunc()
{
keepGoing = confirm( "This is taking a while - do you want to continue?" );
if ( keepGoing )
{
timeoutId = setTimeout( alertFunc, 5000 );
}
}
/**
* Simulation loop
*/
function doWeasel()
{
/** simulation setup */
timeoutId = setTimeout( alertFunc, 5000 );
/** Loop until we find a match or the user gets bored */
while ( keepGoing && matchNotFound )
{
/** do the thing */
}
clearTimeout( timeoutId );
/** some cleanup */
}
That's the basic idea, anyway. The doWeasel function is tied to a button click in a form in the HTML document:
<html>
<head>
<!-- header stuff -->
</head>
<body>
<!-- long-winded explanation -->
<div class="formarea">
<form class="inputForm">
<!-- form stuff -->
<input type="button" value="OK" onclick="doWeasel()"/>
<input type="reset"/>
</form>
</div>
<div id="outputarea">
<h2>Output from the thing</h2>
<script type="text/javascript" src="weasel.js"></script> <!-- source for doWeasel() -->
</div>
</body>
</html>
The problem I'm having is that alertFunc never appears to fire - I've added console logging to write a message when the function is entered, and it never appears. I've run through the debugger in Chrome, with a breakpoint set in the callback, and it's never reached.
Obviously I'm doing something wrong either with the setTimeout call itself or how I'm trying to use it, but based on the documentation I've read so far I don't see what it could be. Is my concept of how to use it just plain wrong?
I'm an old C and C++ programmer who's only dabbled very lightly in HTML and scripting for the Web, so it's possible I just don't understand the right way to do things here.
EDIT
To address some of the comments, this is a working page - when I click OK the simulation runs and dynamically builds a table for output. It’s just that there are combinations of input parameters that cause it to run for an excessively long time (until the browser throws up a "this page is unresponsive" or I just close the tab).
I can trace the execution of the script in the debugger in Chrome, and it calls setTimeout and assigns a value to timerId, but the callback never actually executes. For the default parameters, the simulation runs to completion and builds a table on the page with the results.
Maybe this isn’t the right way to address the issue - maybe I need to add another button that calls a different function setting keepGoing to false.
EDIT2
I wrote up a quick and dirty prototype to just test the timeout functionality, and I think I know what my problem is. If I'm not in the middle of a loop, the callback executes as expected, but if I have a loop spinning it won't. So, I need to do some reading up on how to deal with asynchronous event handling.