Why does this javascript sleep function skip immediately? - javascript

Where isPaused becomes true, the sleep function should go into an infinite loop right??? but for some reason it does not, instead it will print "here2" immediately after? i am using this with an async function which when it is done the bool isPaused becomes false again.
var isPaused = false;
function sleep() {
if (isPaused == true) {
setTimeout(function(){sleep()},1000);
}
};
console.log("here");
isPaused = true;
sleep();
console.log("here 2");
how can i fix it so it will wait, instead of continuing.

If you want to wait for the timer, you need to use a Promise with async and await:
(async () => {
var isPaused = false;
setTimeout(function() {
isPaused = false;
}, 3000);
async function sleep() {
if (isPaused == true) {
await new Promise(resolve => {
setTimeout(async function() {
await sleep();
resolve()
}, 1000);
});
}
return;
}
console.log("here");
isPaused = true;
await sleep();
console.log("here 2");
})();
Here is a JSFiddle.

Your code will run the sleep function, then run it again after 1000 milliseconds.
What your code does:
Set isPaused to false
Define the sleep function (not execute it)
log "here"
Set isPaused to true
Execute the sleep function, it will be called again after 1000ms, but the program doesn't wait for this, so it already executes the next line.
log "here 2"

Because the function sleep is done setting the timeout, so the code can then continue the rest of the operations.
Then after having continued operations for 1s (1000ms) it will perform another sleep, after which it is free to run any other potentially remaining operations.
So the infinite loop does happen, it just doesn't prohibit other code from running.
Try putting a console.log('test') in the first line of the sleep function.
function sleep() {
console.log("test")
if (isPaused == true) {
setTimeout(function(){
sleep()
},1000);
}
};
A little too much to get into here, and others can explain a lot better than me, but look into the JS Event Loop, that should clarify some things!

That's already an infinite loop. Just try to add an "console.log('loop')" inside the setTimeout function and you will see how it's called each second.
Also, remember javascript is not syncronous, so it will print here 2 before the sleep (remember, it requires 1 sec), but it keep working in the infinite loop

Related

Mocking delaying process without using setTimeout

I have created an async function that takes about 2 ~ 3 secs to process. I also have a status polling function that checks if the process is done.
I want to validate this whole process on Jest without using setTimeout. Would it be possible on JS?
let isDone = false;
async function longDelaying() {
// ...
isDone = true;
}
async function poll() {
return isDone;
}
longDelaying();
poll() // -> false
setTimeout(() => {
poll() // -> true
}, 5000);
You could use setInterval to check for its value so many times a second. You can check each time whether the isDone=true. And when it is true you can clear that setInterval function.
It's a dirty trick, though.
The Code for this:
var myChecker = setInterval(function() {
if (isDone){
.... //some process you want to do
clearInterval(myChecker); //removes this function
}
}, 1000); //for checking each 1 second

Can not make a timer with while loop

I am trying to create a timer with while loops and setTimeout but everytime i give an input the code crashes. İ thought doing it this way would work but seems like it doesnt. What is the problem here? And how do i achieve what i want with while loop and setTimeout?
function countdown(durationInput) {
while (durationInput > 0) {
setTimeout(() => {
console.log(durationInput)
durationInput = durationInput - 1
console.log(durationInput)
}, 1000)
}
}
Well look at this image. What you see is the basics of how javascript works.
JS is single threaded. That means 1 core do the work. Thats the event loop.
The event loop grabs the event from the callback queue and put its on the call stack and executes it.
If you run setTimeout you put it into the callback que
The problem: When the event loop is blocked by an synchronouse task like your while loop, that means the event loop cannot grab the events to the stack, because its blocked.
What happens is: The while loop runs and runs and adds more and more setTimeout events to the callback que until the programm crashes.
1 possible solution could be to use promises:
async function sleep(ms) {
return new Promise(res => {
setTimeout(res, ms)
})
}
async function sleep(ms) {
return new Promise(res => {
setTimeout(res, ms)
})
}
async function main() {
console.log("waiting 5 seconds without blocking the main thread")
await sleep(5000)
console.log("done")
}
main()
The problem is that you are generating an infinite loop, as the durationInput doesn't update until the setTimeout executes. And you are filling the execution stack with a huge cue.
For fixing it, you need to create a variable that will store the initial value of the durationInput and subtract from duration in the while loop.
function countdown(duration, intervalInSeconds = 1) {
let count = duration;
while (duration > 0) {
setTimeout(() => {
console.log(count--);
}, intervalInSeconds * 1000);
duration--;
}
}
countdown(10);

Force JavaScript setTimout function to run after x miliseconds

I am trying to make a timeout function that throws an error in case a function hangs for too long.
I have the following code:
function go() {
try{
console.log('started, timeout in 2 seconds...');
setTimeout(()=>{
throw new Error('Timed Out!');
}, 2000);
while(true){
//will run forever
}
}catch (e) {
console.log('timeout function worked!');
}
}
go();
However, the error is never thrown. I think this is because of how the event loop works in JS, but I'd like for my timeout function to execute after 2 seconds regardless of what else is happening. How do I achieve this?
I'd like for my timeout function to execute after 2 seconds regardless of what else is happening. How do I achieve this?
You can't really. As you suspected, the issue is related to the event loop. There's only one thread at your disposal, and you've put it into an infinite loop. Since you never return, the event loop doesn't have a chance to run the function specified by the setTimeout.
If you want your while loop to stop, your while loop needs to be the one to stop it. Perhaps something like this:
const before = Date.now();
while (true) {
// do stuff
if (Date.now() - before > 2000) {
throw new Error('Timed Out!');
}
}
I think this is because you enter inside the infinite loop first and never get out so your settimeout will never fire.
I don't know what your are try to achieve but if you want to throw error, move the while loop inside the settimeout at the end.
By the way that make no sense
setTimeout() doesnot work as you think. Until the while loop is running. The setTimeout() function will not be called.
Javascript doesnot support multithreading because it is an interpreted language.
Multithreading: is a type of execution model that allows multiple threads to exist.See more
Below is the example.
function loop(){
console.time('time');
for(let i = 0;i<10000000;i++){
if(i % 2000000 === 0) console.log("I am looping");
}
console.timeEnd('time');
console.log("Loop finished");
}
loop();
setTimeout(() => {
console.log("I am logged from setTimeout")
},0)
You can't do anything if the event loop can't proceed. But, the below code should be closer to what you are looking for. If you need to do a while statement, do the code further down.
function go() {
try{
var timeout = setTimeout(()=>{
throw new Error('Timed Out!');
}, 2000);
//do stuff; it can't hog the event loop
}catch(e){
}
clearTimeout(timeout);
return true; //return value
}
go();
var iterations = 0;
while(condition && iterations < 10){
//do stuff
iterations++;
}

Using clearInterval within a function to clear a setInterval on another function

I think im missing something fairly obvious with how the clearInterval method works.
So with the code below. I would expect the first function call to execute testFunction and set the interval to repeat the function. The 2nd call would execute the second function which will remove the interval from the 1st function. As this would execute far before the 5000ms interval the first function would not be executed again. However it does not behave like this.
Could someone please explain what is wrong with my method?
Reason for this is in a program I am writing I am making repeated get requests, every 30 seconds or so , using setTimeout but i would like a method to easily remove this interval at other points in the program
function testFunction() {
$("#test").append("test");
setTimeout(testFunction, 5000);
}
function stopFunction() {
clearTimeout(testFunction);
}
testFunction();
stopFunction();
setTimeout returns an ID so you should
var timeoutID = setTimeout(blah blah);
clearTimeout(timeoutID);
setTimeout returns an object that you need to pass into the clearTimeout method. See this article for an example: http://www.w3schools.com/jsref/met_win_cleartimeout.asp
setTimeout returns an identifier for the timer. Store this in a variable like:
var timeout;
function testFunction(){
...
timeout = setTimeout(testFunction, 5000);
}
function stopFunction(){
clearTimeout(timeout);
}
Here is a simple and I think better implementation for this .
var _timer = null,
_interval = 5000,
inProgress = false,
failures = 0,
MAX_FAILURES = 3;
function _update() {
// do request here, call _onResolve if no errors , and _onReject if errors
}
function _start() {
inProgress = true;
_update();
_timer = setInterval(_update, _interval);
}
function _end() {
inProgress = false;
clearInterval(_timer);
}
function _onReject(err) {
if (failures >= MAX_FAILURES) {
_end();
return false;
}
_end();
failures++;
_start();
}
function _onResolve(response) {
return true;
}

Creating a "delay" function in JS?

I've been reading about setTimeout and other such timers. But I'm wondering if it's possible to work up a custom function so that all you would need to do is something like this:
//code
delay(time);
//more code
Is this possible?
UPDATE: Ok, I kind of get it. So if that isn't reasonably possible, how would you go about delaying a loop AFTER the first time. I want it to run immediately upon execution but they delay on each iteration afterward.
New UPDATE: I figure since my initial thought fell through, it might just be easier to show you the code I have.
function autoFarm (clickEvent){
var farmTargets = [
"6_300_1",
"6_300_3",
"6_300_4",
"6_300_5",
"6_300_7"];
setTimeout(function() {
$.each (farmTargets, function(index, target){
var extraData = '{"end_pos":"' + target + '","purpose":0,"upshift":1,"bring_res":{"0":0,"2":0,"1":0},"bring_ship":{"1":25,"11":0},"rate":100,"start_pos":"6_300_2"}';
var finalData = baseDataDora + extraData + "&type=1";
setTimeout(function(){
for (i = 0; i < farmTargets.length; i++){
postRequest(sendFleetURL + getSign(extraData). finalData, function(json){
});
}
}, 15000);
});//End each loop
}, 1320000);
}//End autoFarm
Basically, it should execute immediately and run the for loop 5 times on the first array element 15 seconds apart. Then 22 minutes later move to the next set and repeat for the entire array.
You can achieve something along those lines with generators. The idea is that continuation passing style (callback hell) can be flattened. The generator uses the yield keyword to pause the function, until the callback resumes it by calling its next method:
var async = function(gen) {
var g = gen()
function next(x) {
var cur = g.next(x)
if (cur.done) {
return cur.value
}
cur.value(next)
}
next()
}
var delay = function(time) {
return function(f) {
setTimeout(f, time)
}
}
async(function* () {
console.log('before')
yield delay(1000) // waits one second
console.log('middle')
yield delay(1000) // waits one second
console.log('after')
})
In CPS it would read something like:
console.log('before')
setTimeout(function() {
console.log('middle')
setTimeout(function() {
console.log('after')
}, 1000)
}, 1000)
This works in Chrome, Firefox and iojs today.
This isn't possible because of the way single-threaded event loops work. If this function were to exist, it would cause the entire UI thread to freeze until the delay was satisfied. setTimeout(cb, delay) is the nearest facility which schedules a function to be executed no earlier than the delay and at the end of the current event loop tick.
Update: Before somebody calls me on it, yes, you can theoretically engineer a delay function that freezes everything in place for a set amount of time. However, there is no reasonable excuse to do it this way.
To your second question:
function hello() {
console.log('hello');
}
// execute immediately
hello();
// then every 5 seconds
setInterval(hello, 5000);
As-written, no that's not possible.
If, instead you were to use a queue, delays in that manner are trivial.
jQuery's .queue() and .delay() functions are a good example of how this works, so I will use them as an example, however the general point stands for any queueing library.
Instead of:
//code
delay(time)
//more code
With a queue, you'd write:
$('...') //some selector to act on for jQuery
.queue(function (next) {
//code
//Indicate that the queued call is finished.
next();
//This allows async code to be executed in the queue,
//such as ajax and animations
})
.delay(time)
.queue(function (next) {
//more code
next();
});
Now, even if you ignore the lines used for comments, you can tell that there's a bit more boilerplate to achieve the desired behavior. I don't feel that it's excessive, because I find it relatively easy to read:
queue something to happen
wait for some number of milliseconds
queue something else to happen
Using a Promise, calling it inside an asynchronous function.
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const any_function = async() => {
await delay(2000);
console.log('this log has been delayed 2 secs')
}

Categories

Resources