I have a loop that runs indefinitely until I tell it to stop. I am actually using requestAnimationFrame and a lot more is going on, but the below example is just to simplify my question.
var _stop = false;
var loop = function () {
while (!_stop) {
if (some condition is met) {
stop();
}
/* Do something. */
loop();
}
};
function stop() {
_stop = true;
}
Now this all works great, but it will still run /* Do something */ one more time before it actually stops. I want it to stop immediately and return.
Of course this can be done like so:
if (some condition is met) {
stop();
return;
}
But is there a way to include the return part into stop();? This doesn't do what I want for obvious reasons:
function stop() {
_stop = true;
return;
}
But is there a way to achieve this?
var _stop = false;
try {
var loop = function () {
if(!_stop) {
if (some condition is met) {
stop();
}
/* Do something. */
loop();
}
};
} catch(e) {
}
function stop() {
_stop = true;
throw new Error("USE IT WITH PRECAUTION");
}
The loop above does you job of exiting entire loop, But I will say its horribly wrong way of doing thing as ideally function should be
1) mutating the state variables
2) or should be computing the values.
3) or should be determining error state to stop the execution further
It should never be bothered about how the control flow of function caller is and ways to stop function caller execution flow.
It sounds like you want to check the condition (before) every time the work is done. To do this with a _stop variable (as opposed to simply checking the condition in the while condition itself), you have to:
Set the variable based on the condition before starting the loop
Do your work
Set the variable based on the condition before the next loop iteration
Whether you accomplish this with a while() loop or a do while() loop, the process will be the same. Adding a pre-loop check to your example will prevent the work from being done if the user has already exited:
var _stop = false;
// Call loop() when required
var loop = function () {
// Check condition before first iteration
if (/* some condition is met */) {
stop();
}
while (!_stop) {
/* Do your work */
// Check condition before every subsequent iteration
if (/* some condition is met */) {
stop();
}
loop();
}
};
function stop() {
_stop = true;
}
Is there a reason you are recursively calling loop() instead of calling it once and doing all of your work within the contained loop until the user exits? This more simplified version might work for you:
var _stop = false; // Set it initially, could also use checkStopRequired() here
// Call loop() when required
var loop = function () {
// Check condition before first iteration
_stop = checkStopRequired();
while (!_stop) {
// Do your work, setting _stop to true if work returns early
_stop = !doMyWork();
// Check condition before every subsequent iteration
_stop = checkStopRequired();
}
};
function checkStopRequired() {
// Return true if should stop, false if should continue
}
When doing the work required for each loop iteration, you may want to check the exit condition before any expensive operations to allow the whole thing to halt as soon as an exit condition is met, as opposed to waiting for the work to finish. This obviously depends on what work you're doing and what the exit conditions are.
An example of the function to be called within the loop, which will help you set _stop if the stop condition is met part-way through:
function doMyWork() {
// Get user input here...
if (checkStopRequired()) { return false; }
// Get data here...
if (checkStopRequired()) { return false; }
// Do logic here...
if (checkStopRequired()) { return false; }
// Render objects here...
// Return successful result
return true;
}
it might not be the optimal way to do this, but this can be done like this:
var _stop = false;
var flag=0;
var loop = function () {
if(!_stop) {
if(flag){
return;
}
if (some condition is met) {
stop();
_stop = true;
loop();
}
/* Do something. */
loop();
}
};
function stop() {
//_stop = true;
toReturn();
}
function toReturn(){
flag=1;
}
Related
I know how to execute a function once, this is not the question
First, this is my code
var executed1 = false;
var executed2 = false;
var executed3 = false;
function myFunction()
{
if(-------------------)
{
//Verification - If the others conditions have ever been called
if (executed2)
{
executed2 = false;
}
else if(executed3)
{
executed3 = false;
}
//Verification - If the condition have ever been called during this condition = true;
if (!execution1)
{
execution1 = true;
//My code here ...
}
}
else if (-------------------)
{
if (executed1)
{
executed1 = false;
}
else if(executed3)
{
executed3 = false;
}
if (!execution2)
{
execution2 = true;
//My code here ...
}
}
else if (-------------------)
{
//Same thing with execution3
}
}
setInterval("myFunction()", 10000);
I'll take the first condition, for example
(1) If the condition is true, I want to execute my code but only the first time : as you can see, my function is executed every 10s. As long as the first condition is true, nothing should append more.
If the first condition becomes false and the second condition true, it’s the same process.
But now, If the first condition ever been true and false, I would like that if the condition becomes true again, it will be the same thing that (1)
Is there any way to read a cleaner code to do that ?
Because, now there are only 3 conditions, but there may be 100.
use clearInterval to stop execution your function and one if to check conditions
var fid = setInterval(myFunction, 1000);
var cond = [false,false,false];
function myFunction()
{
console.log(cond.join());
// check conditions in some way here (e.g. every is true)
if(cond.every(x=>x)) {
clearInterval(fid);
console.log('Execute your code and stop');
}
// change conditions (example)
cond[2]=cond[1];
cond[1]=cond[0];
cond[0]=true;
}
I have an application using jquery that iterates through a series of checkboxes.
while it iterates through, I have a dialog showing the status of the printing session. I also have a cancel button to cancel the session.
<input type="button" id="cancelButton" onclick="cancel()">
function cancel() {
stop = true;
}
Through each iteration I check if stop is true and if it is, I break out of the loop. The problem however is that if I press the cancel button during the session, the cancel function will only run after the .each loop (kind of defeating the purpose). Is there a way to make the button more responsive or a better way to approach this?
Run the functions in separate threads?
setTimeout(function() { $('[name=check]:checked').each(function() {
printingFunction();
}); }, 1);
You could chain setTimeouts in order to make it possible to check for a Stop. You'd still have to wait for the current operation to complete, but it would let you break out of the loop.
function next()
{
printingFunction();
if (!stop && someOtherCheck)
setTimeout(function() { next(); }, 1);
}
next();
I don't think you can interrupt the .each loop as JavaScript execution is single threaded.
However I think timers are executed asynchronously, you might try something like below to cancel and clear.
Something like the logic below may get you there.
var timeouts = [];
$.each(someArray, function(index, value){
timeouts.push(setTimeout(function(){
console.log(index);
},5000*index));
});
$('#cancel-button').click(function(){
$.each(timeouts, function (_, id) {
clearTimeout(id);
});
timeouts = [];
}):
Also, you may consider playing with .index() if the above doesn't help.
Try it again - I made a change to the shift statement that will clear the error in IE 11:
var ele = Array.prototype.shift.call($checked);
You need to use setTimeout on the each loop call (can be set to 0) so the cancel function gets a chance to execute - something like this:
function cancel() {
stop = true;
}
function printingFunction() {
var x = 0;
while (x < 10000){
x+=1;
}
}
function printLoop($checked) {
if (stop) {
console.log('Stopped - button pushed')
} else {
if ($checked.length > 0) {
var ele = Array.prototype.shift.call($checked);
printingFunction()
}
if ($checked.length > 0) {
setTimeout(function(){printLoop($checked)}, 0);
} else {
console.log('Stopped - array depleted')
}
}
}
var stop = false,
$checked = $('[name=check]:checked');
printLoop($checked)
This question already has answers here:
Implementing a pause and resume mechanism for javascript loop execution
(2 answers)
Closed 7 years ago.
I have a start button that when clicked runs a function that loops. How do I get a stopBTN.onClick to stop the running loop?
https://jsfiddle.net/vduxbnkj/
startBTN.onClick = function(){ runLoop(); }
function runLoop(){
while(condition true){
getFolderContentsLoop();
}
}
function getFolderContentsLoop(){
//loop through folders & files looking for .txt file and if "finished"
delete files and folders
}
If you're running a simple for (..) loop, this cannot be stopped via external influence. Everything is happening on the same thread in Javascript, unless your code "ends" at some point and returns control to the browser for a while no UI interaction can happen. The easiest way to have a "loop" is via a setTimeout or setInterval:
interval = null;
startBTN.onclick = function () {
var i = 0;
interval = setInterval(function () {
console.log(i++); // this is inside your loop
}, 1);
};
stopBTN.onclick = function () {
clearInterval(interval);
};
Javascript is single threaded and as long it is in a loop, it can't give control to other code to stop it. But if you have a special kind of loop that is implemented with setTimeout:
function loopStep() {
...
}
function loop() {
loopStep();
setTimeout(loop, 0);
}
then you can add a flag to be able to stop loop's execution:
var flag = true;
function loop() {
if (!flag) return;
loopStep();
setTimeout(loop, 0);
}
and then you can define your stop function:
function stop() {
flag = false;
}
I usually work around this by making my own boolean test as the while condition, like so:
var keepLooping = false;
while(!keepLooping){
document.getElementById("loopButton").onclick = function(){
keepLooping = true;
}
}
while(keepLooping){
//do something here
document.getElementById("loopButton").onclick = function(){
keepLooping = false;
}
}
The only method I can think of is to create a boolean at the very beginning, and set stopBTN.onclick as a function that switches the variable. Then put an if condition that uses break if the boolean is switched.
var r = false;
startBTN.onClick = function(){ runLoop(); }
stopBTN.onClick = function(){r = true; }
function runLoop(){
while(condition true){
getFolderContentsLoop();
if(r){
break;
}
}
}
function getFolderContentsLoop(){
/*loop through folders & files looking for .txt file and if "finished"
delete files and folders*/
}
It's crude, but it should work.
I have the following jquery code with setTimeout function to set a variable to false but it never works and the variable always remains to be true
for( var ff = 0; ; ff++)
{
if( dif == 0){
break;
}
if (locked){
// locked = false;
setTimeout( function(){ locked = false; },2000);
}
else{
LeftKeyPressed();
locked = true ;
setTimeout( function(){ locked = false; },3000);
dif--;
}
}
can anyone to help in how to set the locked variable to false after exactly two seconds from setting it to true.
Here's a fiddle of this issue.
Okey, since the requirements are what they are I dont know what exactly you want but this is closest I could manage to make: http://jsfiddle.net/db6gJ/
It calls method three times and gives you a change to do what you want to do when locked is false or true. Plus, it won't block the event loop (with that infinite for loop) so your site can make other tasks while timeOut call's are running.
javascript code also here:
var locked = true,
timesMax = 3,
timeCurrent = 0;
var inputLoop = function() {
var delay = 2000;
if(locked) {
// Do something when locked is true
console.log("locked is true!");
locked = false;
} else {
// Do something when locked is false
console.log("locked is false!");
locked = true;
delay = 3000;
}
timeCurrent++;
// call again after delay, but call only 3 times
if(timeCurrent < timesMax) {
setTimeout(inputLoop, delay);
}
};
// Launch it
inputLoop();
If you view your javascript console (in chrome: right mouse click -> inspect element -> console) it should print:
locked is true!
locked is false!
locked is true!
Also to be noted: your original code had alert('out'); when it's done, but to be honest, code will continue execution elsewhere while your "inputLoop" code is not doing anything else than waiting callback to be run and it's the way it should be.
If you wan't to know when it is called last time you could modify one of the previous lines to be:
// call again after delay, but call only 3 times
if(timeCurrent < timesMax) {
setTimeout(inputLoop, delay);
} else {
// Last call in this method
console.log('done!');
}
I have a setInterval calling a loop which displays an animation.
When I clearInterval in response to a user input, there are possibly one or more loop callbacks in queue. If I put a function call directly after the clearInterval statement, the function call finishes first (printing something to screen), then a queued loop callback executes, erasing what I wanted to print.
See the code below.
function loop() {
// print something to screen
}
var timer = setInterval(loop(), 30);
canvas.onkeypress = function (event) {
clearInterval(timer);
// print something else to screen
}
What's the best way to handle this? Put a delay on the // print something else to screen? Doing the new printing within the loop?
Edit: Thanks for the answers. For future reference, my problem was that the event that triggered the extra printing was buried within the loop, so once this executed, control was handed back to the unfinished loop, which then overwrote it. Cheers.
You could also use a flag so as to ignore any queued functions:
var should;
function loop() {
if(!should) return; // ignore this loop iteration if said so
// print something to screen
}
should = true;
var timer = setInterval(loop, 30); // I guess you meant 'loop' without '()'
canvas.onkeypress = function (event) {
should = false; // announce that loop really should stop
clearInterval(timer);
// print something else to screen
}
First of all, you probably meant:
var timer = setInterval(loop, 30);
Secondly, are you sure calling clearInterval does not clean the queue of pending loop() calls? If this is the case, you can easily disable these calls by using some sort of guard:
var done = false;
function loop() {
if(!done) {
// print something to screen
}
}
var timer = setInterval(loop(), 30);
canvas.onkeypress = function (event) {
clearInterval(timer);
done = true;
// print something else to screen
}