I am currently looking for a way to timeout on a synchonous JavaScript code using node.
In a nutshell: I have a synchronous code which takes too long (for instance: an infinite loop). I would be interesting in stopping its run.
On async function
I found a way to do it on asynchronous calls using Promise.race with a custom delay promise which ends after Xxx milliseconds.
For asynchronous functions the code is the following:
function timeoutIt(fun, timeMs) {
return Promise.race([
fun(),
new Promise((resolve, reject) => setTimeout(reject, timeMs))
]);
}
I tried to derive this snippet to receive my synchronous function, but once the function has been called the reject Promise is never executed. Any idea to have some kind of timeout on synchronous code?
Context: I am currently working on a property based testing framework
https://github.com/dubzzz/fast-check and wanted to be able to work
even for disruptive cases where the code goes into infinite loops. For
the moment, the code holds and wait for the test framework to timeout
on its side
Thanks in advance for your help
In your example the reject function doesn't work because javascript is single threaded.
In reality, the setTimeout function is working, but runs outside of the javascript thread(in browser queue system, or in your case by the node.js queue system (libuv), when setTimeout finished, the handler (the code you want to execute when the timeout finish) is inserted in a event queue and prepared to be executed for javascript throught the event loop, but, the problem is that the event loop is processing the code of your synchronous code, and never reach your handler.
This is an "homemade" example to stops a infite loop:
function longTimeFunction(timeAllowedInSeconds) {
function getCurrentTime() {
return new Date().getTime() / 1000;
}
const startTime = getCurrentTime();
let stopLoop = false;
let currentTime;
while(1 && !stopLoop) { //infinite loop
//your code here, for example:
console.log(Math.random());
currentTime = Math.round(getCurrentTime() - startTime);
if (currentTime >= timeAllowedInSeconds) {
stopLoop = true;
}
}
};
longTimeFunction(3);
To help you understand the how deal with sync and async in javascript I put here one amazing video:
Philip Roberts: What the heck is the event loop anyway? | JSConf EU 2014
Related
The following example is given in a Node.js book:
var open = false;
setTimeout(function() {
open = true
}, 1000)
while (!open) {
console.log('wait');
}
console.log('open sesame');
Explaining why the while loop blocks execution, the author says:
Node will never execute the timeout callback because the event loop is
stuck on this while loop started on line 7, never giving it a chance
to process the timeout event!
However, the author doesn't explain why this happens in the context of the event loop or what is really going on under the hood.
Can someone elaborate on this? Why does node get stuck? And how would one change the above code, whilst retaining the while control structure so that the event loop is not blocked and the code will behave as one might reasonably expect; wait
will be logged for only 1 second before the setTimeout fires and the process then exits after logging 'open sesame'.
Generic explanations such as the answers to this question about IO and event loops and callbacks do not really help me rationalise this. I'm hoping an answer which directly references the above code will help.
It's fairly simple really. Internally, node.js consists of this type of loop:
Get something from the event queue
Run whatever task is indicated and run it until it returns
When the above task is done, get the next item from the event queue
Run whatever task is indicated and run it until it returns
Rinse, lather, repeat - over and over
If at some point, there is nothing in the event queue, then go to sleep until something is placed in the event queue or until it's time for a timer to fire.
So, if a piece of Javascript is sitting in a while() loop, then that task is not finishing and per the above sequence, nothing new will be picked out of the event queue until that prior task is completely done. So, a very long or forever running while() loop just gums up the works. Because Javascript only runs one task at a time (single threaded for JS execution), if that one task is spinning in a while loop, then nothing else can ever execute.
Here's a simple example that might help explain it:
var done = false;
// set a timer for 1 second from now to set done to true
setTimeout(function() {
done = true;
}, 1000);
// spin wait for the done value to change
while (!done) { /* do nothing */}
console.log("finally, the done value changed!");
Some might logically think that the while loop will spin until the timer fires and then the timer will change the value of done to true and then the while loop will finish and the console.log() at the end will execute. That is NOT what will happen. This will actually be an infinite loop and the console.log() statement will never be executed.
The issue is that once you go into the spin wait in the while() loop, NO other Javascript can execute. So, the timer that wants to change the value of the done variable cannot execute. Thus, the while loop condition can never change and thus it is an infinite loop.
Here's what happens internally inside the JS engine:
done variable initialized to false
setTimeout() schedules a timer event for 1 second from now
The while loop starts spinning
1 second into the while loop spinning, the timer is ready to fire, but it won't be able to actually do anything until the interpreter gets back to the event loop
The while loop keeps spinning because the done variable never changes. Because it continues to spin, the JS engine never finishes this thread of execution and never gets to pull the next item from the event queue or run the pending timer.
node.js is an event driven environment. To solve this problem in a real world application, the done flag would get changed on some future event. So, rather than a spinning while loop, you would register an event handler for some relevant event in the future and do your work there. In the absolute worst case, you could set a recurring timer and "poll" to check the flag ever so often, but in nearly every single case, you can register an event handler for the actual event that will cause the done flag to change and do your work in that. Properly designed code that knows other code wants to know when something has changed may even offer its own event listener and its own notification events that one can register an interest in or even just a simple callback.
This is a great question but I found a fix!
var sleep = require('system-sleep')
var done = false
setTimeout(function() {
done = true
}, 1000)
while (!done) {
sleep(100)
console.log('sleeping')
}
console.log('finally, the done value changed!')
I think it works because system-sleep is not a spin wait.
There is another solution. You can get access to event loop almost every cycle.
let done = false;
setTimeout(() => {
done = true
}, 5);
const eventLoopQueue = () => {
return new Promise(resolve =>
setImmediate(() => {
console.log('event loop');
resolve();
})
);
}
const run = async () => {
while (!done) {
console.log('loop');
await eventLoopQueue();
}
}
run().then(() => console.log('Done'));
Node is a single serial task. There is no parallelism, and its concurrency is IO bound. Think of it like this: Everything is running on a single thread, when you make an IO call that is blocking/synchronous your process halts until the data is returned; however say we have a single thread that instead of waiting on IO(reading disk, grabbing a url, etc) your task continues on to the next task, and after that task is complete it checks that IO. This is basically what node does, its an "event-loop" its polling IO for completion(or progress) on a loop. So when a task does not complete(your loop) the event loop does not progress. To put it simply.
because timer needs to comeback and is waiting loop to finish to add to the queue, so although the timeout is in a separate thread, and may indeed finsihed the timer, but the "task" to set done = true is waiting on that infinite loop to finish
var open = false;
const EventEmitter = require("events");
const eventEmitter = new EventEmitter();
setTimeout(function () {
open = true;
eventEmitter.emit("open_var_changed");
}, 1000);
let wait_interval = setInterval(() => {
console.log("waiting");
}, 100);
eventEmitter.on("open_var_changed", () => {
clearInterval(wait_interval);
console.log("open var changed to ", open);
});
this exemple works and you can do setInterval and check if the open value changed inside it and it will work
I am trying to figure out why in my Code section, this.sleep(5000) seems to be getting called before my draw function, because it doesn't get drawn to the canvas until after sleep is done. any insights on why this isn't working the way I want it to?
Sleep function:
sleep: function(milliseconds) {
setTimeout(function(){
var start = new Date().getTime();
while ((new Date().getTime() - start) < milliseconds){
// Do nothing
}
},0);
},
Code:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx,"blue");
this.sleep(5000);
Short answer
Don't do it this way. Even if you get it to work, it will be inconsistent, will cause you many problems, and is almost globally considered bad practice.
Long answer
JavaScript runtimes are almost always designed to be asynchronous. Your while loop is intended to make everything... wait. You cannot (or at least shouldn't) do that in most JavaScript environments.
Instead, schedule events/functions to be executed some number of ms in the future. This is what setTimeout is for. This removes the need for a sleep function.
Here's what your code might look like after the changes described above are applied:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx, "blue");
setTimeout(function() {
g.DrawPolygons(ctx, "red"); // Or whatever
setTimeout(function() {
g.DrawPolygons(ctx, "yellow"); // Or whatever
// etc..
}, 5000);
}, 5000);
ES2015 update - using promises
To avoid potential deeply nested setTimeouts, you can use this
const sleep ms = new Promise(resolve => setTimeout(resolve,ms));
which is simply a promise that resolves in ms milliseconds. This allows you to keep everything in one block:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx, "blue");
(async () => {
g.DrawPolygons(ctx, "red");
await sleep(5000);
g.DrawPolygons(ctx, "yellow");
await sleep(5000);
// ...
})()
Note two things:
Under the hood, there are still events/callback. It looks like C's or Python's sleep but behave very differently.
You can only use this inside asynchronous functions. See here for more information.
There are several problems with the code you've posted. First off, you should never use a while loop to halt code execution.
Secondly, you're setting a timeout, which allows other code to be executed in the interim (yes, even if the timeout is zero seconds). Remove that and you should be able to pause execution (BUT DON'T DO THIS):
sleep: function(milliseconds) {
var start = new Date().getTime();
while ((new Date().getTime() - start) < milliseconds){
// Do nothing
}
},
However, occupying the JS thread means that other browser operations (redraws, etc) will be halted until your sleep function exits. Just having this code in your JS file is an antipattern, you'd be better off finding a different way to solve your problem. Read up on the XY problem and ask a new question.
In case all you wanted to do was execute some code after a certain interval without blocking everything else, setTimeout is all you need.
sleep: function(ms, funcToExecute) {
setTimeout(funcToExecute, ms);
},
(Though at this point, sleep is redundant)
This is happening because of how JavaScript's setTimeout works. When you do:
setTimeout(function(){}, 0)
You are not actually telling it to run the function after 0ms (the lowest value is actually 4ms, but that's besides the point). You are telling it to run the function in the future. What it actually does is put the function at "the end of the stack". It'll finish running the function that called it, and maybe even run some UI redraws before it runs the timeout.
If this code is ran in a loop, your timeouts will not run at all when you think they will ;)
Also, remember JavaScript is single threaded. One thread runs your code as well as the UI redraws. Doing a while loop that does nothing and waits for 5 seconds will lock up the browser. It will prevent any user interaction and UI redraws. It might even make the OS think the browser crashed. DO NOT DO THIS!
Instead, try setting a timeout to run the next polygon after 5000ms:
var g = new Graph(this.diagram);
g.DrawPolygons(ctx,"blue");
setTimeout(function(){
// Code to run after the "sleep"
// Maybe another shape
g.DrawPolygons(ctx, "red");
}, 5000);
I'm trying to return a variable only after it has been set within a setTimeout callback. I couldn't think of any other way to do this, but here's my attempt (I know the code seems silly, but it's to work around a Cordova bug). For reasons beyond my understanding, it results in an infinite loop.
function isConnected() {
var done = false;
setTimeout(function() {
done = true;
}, 500);
while (!done) {}
return navigator.connection.type!== Connection.NONE;
}
Can anyone explain to me why this is happening, or provide an alternative?
Update (solution):
function isConnected(callback) {
setTimeout(function() {
callback(navigator.connection.type !== Connection.NONE);
}, 500);
}
isConnected(function(connected) {
if (!connected)
alert('Not Connected');
});
You simply can't solve your problem that way. Because javascript is single threaded, the setTimeout callback can only run when your JS thread of execution finishes so with your infinite loop, it will never get to run and your code will hang. Eventually the browser will complain about a long-running piece of JS and offer to shut it down.
Instead, you need to use a callback function on the setTimeout() and continue your code from that callback. You can't use sequential code for timeouts. You must use asynchronous coding styles.
You could do something like this where you pass in a callback and it calls the callback back and passes it the connected boolean:
function GetConnectedState(callback) {
setTimeout(function() {
callback(navigator.connection.type !== Connection.NONE);
}, 500);
}
Your existing code doesn't seem to offer anything other than a look at the connection state in 1/2 second. With any real sort of asynchronous operation in javascript (such as an ajax call or a websocket connection), there should also be a success or completion callback that will tell you when/if the operation actually completes and you can also trigger the callback based on that (sooner than 1/2 second most of the time). So, this doesn't really look like a complete solution, but it's all you show us you're using.
For example, here's an answer you can look at that calls a callback when an images loads successfully, with an error or times out with no response: Javascript Image Url Verify and How to implement a "function timeout" in Javascript - not just the 'setTimeout'. A similar concept could be used for implementing your own timeout on some other type of asynchronous call.
As I revisit this 5 years later, can't help but to offer up a fancier alternative:
await new Promise(function(resolve) {
setTimeout(resolve, 500);
});
if (navigator.connection.type === Connection.NONE) {
alert('Not Connected');
}
Javascript is single-threaded. The timeout function can't run until your script returns to the main event loop. But as long as you're in the while loop it will never return, so the timeout function never runs, so done is never set to true.
It's not possible in Javascript to wait for an asynchronous event before returning.
Why there no such function in javascript that sets a timeout for its continuation, saves the necessary state (the scope object and the execution point), terminates the script and gives the control back to the browser? After the timeout expires the browser would load back the execution context and continues the script, and we would have a real non browser blocking sleep functionality that would work even if the JS engine is single threaded.
Why there is still no such functionality in javascript? Why do we have to still slice our code into functions and set the timeouts to the next step to achieve the sleep effect?
I think 'sleep'ing is something you do not want in your browser.
First of all it might be not clear what has to happen and how a browser should behave when you actually sleep.
Is the complete Script runtime sleeping? Normally it should because you only have one thread running your code. So what happens if other events oocur during sleep? they would block, and as soon execution continues all blocked events would fire. That will cause an odd behaviour as you might imagine (for instance mouse click events which are fired some time, maybe seconds, after the actual click). Or these events had to be ignored, which will lead to a loss of information.
What will happen to your browser? Shall it wait for sleep if the user clicks a (e.g. close window) button? I think not, but this might actually call javascript code again (unload) which will not be able to be called since program execution is sleeping.
On a second thought sleep is a sign of poor program design. Actually a program/function/you name it has a certain task, which shall be completed as soon as possible. Sometimes you have to wait for a result (for instance you wait for an XHR to complete) and you want to continue program execution meanwhile. In this case you can and should use asynchronous calls. This results in two advantages:
The speed of all scripts is enhanced (no blocking of other scripts due to sleep)
The code is executed exactly when it should and not before or after a certain event (which might lead to other problems like deadlocks if two functions check for the same condition ...)
... which leads to another problem: Imagine two or more pieces of code would call sleep. They would hinder themselves if they try to sleep at the same, maybe unnecessarily. This would cause a lot of trouble when you like to debug, maybe you even have difficulties in ensuring which function sleeps first, because you might control this behavior somehow.
Well I think that it is one of the good parts of Javascript, that sleep does not exist. However it might be interesting how multithreaded javascripts could perform in a browser ;)
javascript is desgined for single process single thread runtime, and browser also puts UI rendering in this thread, so if you sleep the thread, UI rendering such as gif animation and element's event will also be blocked, the browser will be in "not responding" state.
Maybe a combination of setTimeout and yield would work for your needs?
What's the yield keyword in JavaScript?
You could keep local function scope while letting the browser keep going about its work.
Of course that is only in Mozilla at the moment?
Because "sleep()" in JavaScript would make for a potentially horrible user experience, by freezing the web browser and make it unresponsive.
What you want is a combination of yield and Deferreds (from jquery for example).
It's called sometimes pseudoThreads, Light Threading or Green Threads. And you can do exactly what you want with them in javascript > 1.7 . And here is how:
You'll need first to include this code:
$$ = function (generator) {
var d = $.Deferred();
var iter;
var recall = function() {
try {var def = iter.send.apply(iter, arguments);} catch(e) {
if (e instanceof StopIteration) {d.resolve(); return;}
if (e instanceof ReturnValueException) {
d.resolve(e.retval); return
};
throw e;
};
$.when(def).then(recall); // close the loop !
};
return function(arguments) {
iter = generator.apply(generator, arguments);
var def = iter.next(); // init iterator
$.when(def).then(recall); // loop in all yields
return d.promise(); // return a deferred
}
}
ReturnValueException = function (r) {this.retval = r; return this; };
Return = function (retval) {throw new ReturnValueException(retval);};
And of course call jquery code to get the $ JQuery acces (for Deferreds).
Then you'll be able to define once for all a Sleep function:
function Sleep(time) {
var def = $.Deferred();
setTimeout(function() {def.resolve();}, time);
return def.promise();
}
And use it (along with other function that could take sometime):
// Sample function that take 3 seconds to execute
fakeAjaxCall = $$(function () {
yield (Sleep(3000));
Return("AJAX OK");
});
And there's a fully featured demo function:
function log(msg) {$('<div>'+msg+'</div>').appendTo($("#log")); }
demoFunction = $$(function (arg1, arg2) {
var args = [].splice.call(arguments,0);
log("Launched, arguments: " + args.join(", "));
log("before sleep for 3secs...");
yield (Sleep(3000));
log("after sleep for 3secs.");
log("before call of fake AjaxCall...");
ajaxAnswer = yield (fakeAjaxCall());
log("after call of fake AjaxCall, answer:" + ajaxAnswer);
// You cannot use return, You'll have to use this special return
// function to return a value
log("returning 'OK'.");
Return("OK");
log("should not see this.");
});
As you can see, syntax is a little bit different:
Remember:
any function that should have these features should be wrapped in $$(myFunc)
$$ will catch any yielded value from your function and resume it only when
the yielded value has finished to be calculted. If it's not a defered, it'll work
also.
Use 'Return' to return a value.
This will work only with Javascript 1.7 (which is supported in newer firefox version)
It sounds like what you're looking for here is a way to write asynchronous code in a way that looks synchronous. Well, by using Promises and asynchronous functions in the new ECMAscript 7 standard (an upcoming version of JavaScript), you actually can do that:
// First we define our "sleep" function...
function sleep(milliseconds) {
// Immediately return a promise that resolves after the
// specified number of milliseconds.
return new Promise(function(resolve, _) {
setTimeout(resolve, milliseconds);
});
}
// Now, we can use sleep inside functions declared as asynchronous
// in a way that looks like a synchronous sleep.
async function helloAfter(seconds) {
console.log("Sleeping " + seconds + " seconds.");
await sleep(seconds * 1000); // Note the use of await
console.log("Hello, world!");
}
helloAfter(1);
console.log("Script finished executing.");
Output:
Sleeping 1 seconds.
Script finished executing.
Hello, world!
(Try in Babel)
As you may have noticed from the output, this doesn't work quite the same way that sleep does in most languages. Rather than block execution until the sleep time expires, our sleep function immediately returns a Promise object which resolves after the specified number of seconds.
Our helloAfter function is also declared as async, which causes it to behave similarly. Rather than block until its body finishes executing, helloAfter returns a Promise immediately when it is called. This is why "Script finished executing." gets printed before "Hello, world!".
Declaring helloAfter as async also allows the use of the await syntax inside of it. This is where things get interesting. await sleep(seconds * 1000); causes the helloAfter function to wait for the Promise returned by sleep to be resolved before continuing. This is effectively what you were looking for: a seemingly synchronous sleep within the context of the asynchronous helloAfter function. Once the sleep resolves, helloAfter continues executing, printing "Hello, world!" and then resolving its own Promise.
For more information on async/await, check out the draft of the async functions standard for ES7.
I know this is bad:
function sleep(millis) {
var date = new Date();
var curDate = null;
do { curDate = new Date();
} while(curDate-date < millis);
}
EDIT:
function doSomethingQuickly(pixelData) {
// loads an external image, filling the entire screen
// overlays $pixelsData over image
}
But I really do need this sort of functionality since doSomethingQuickly() returns so fast and the other doSomethingQuickly()'s cannot be allowed to run until the previous is finished. It would be disastrous to simply fire them all off and wait for results to deal with them.
doSomethingQuicky();
sleep(500);
doSomethingQuicky();
sleep(500);
doSomethingQuicky();
sleep(500);
doSomethingQuicky();
sleep(500);
doSomethingQuicky();
sleep(500);
My question is that since simulating sleep in JS is bad, how can I achieve the same using setTimeout() or another more acceptable method
NOTE: this is not in a web browser
EDIT:
You can see that if it ran 5 times without the sleep, it would quickly show the final image, when what it should do is 1) show an image 2) pause for 5 seconds 3) repeatYou can see that if it ran 5 times without the sleep, it would quickly show the final images, when what it should do is 1) show an image 2) pause for 5 seconds 3) repeat
How about:
function sleep(ms,callback){
setTimeout(callback,ms);
}
//basic usage
while (someStoppingcondition){
sleep(500,doSomethingQuicky);
}
if doSomethingQuicky is always the same function, setInterval (see other answers) is sufficient. Make sure it will not run forever, use clear[Interval/Timeout] to stop the timers.
if your problem is that one function has to complete before the next one executes, this may be a way to solve it:
function firstRunner(arg1,arg2,/* ... argx*/, nextRunner){
//do things
//after things are done, run nextRunner
nextRunner();
}
JavaScript is single-threaded. Any series of doSomethingQuicky(); should execute sequentially.
That is unless you're using some timer functions within doSomethingQuicky();. Without knowing what this function does, it's hard to advise.
var interval = setInterval(doSomethingQuickly, 500)
...
clearInterval(interval);
I don't know what the code is doing. JavaScript is single threaded so you shouldn't hit any problems. You also shouldn't sleep as it sleeps the only thread.
Using sleeps to wait for a function to return is always a bad idea. What if the slow function takes more time than predicted? What about time performance issues regarding the time spent idling?
Use promises instead:
// resolves immediatly to the string 'fast done'
const fast = new Promise(resolve => resolve('fast done'));
// resolves after 1 second to the string 'slow done'
const slow = new Promise(resolve => setTimeout(() => resolve('slow done'), 1000));
// resolves after 1 second to the array ['fast done', 'slow done'], then logs it for demo purposes
Promise.all([fast, slow]).then(console.log);
I think that Promise.all is exaclty what you're looking for. It resolves when all the promises that it gets as argument resolve, so you can pass it several functions with different execution time, and continue the code when all the functions have returned.