I'm making a little game, and i was making a character death sequence when I ran into this problem. The
eloop(setInterval(e_seq,100)
plays the ending sequence. After that, I want execution to stop for a second before displaying the score and stuff.
But the current sleep method i'm using pauses the entire execution, including the loop, while I want the loop to be completed before pausing the game for a second.
The place where sleep is called: (inside the main gameloop)
eloop=setInterval(e_seq,100);
sleep(1000);
The sleep method:
function sleep(msec)
{
var time= new Date().getTime();
while(time+msec>= new Date().getTime())
{}
}
any solutions?
PS: calling sleep at the end of the gameloop (inside an if condition checker) was pausing the execution before the gameloop began for some reason....
I think you probably want something more along the lines of
setTimeout(function () { e_seq(); }, 1000);
This would wait one second and then execute the e_seq() function, which I think is the purpose of your code, although it's open to a little interpretation...
Did you try just the setInterval?
setInterval(function(){ ... }, 3000);
i have tried something
var looper;
var looptime = 2000;
var doloop = function(){
console.log("doing this")
}
function begin(callthis){
looper = setInterval(callthis,looptime);
}
function pause(callthis,sleeptime){
clearInterval(looper);
setTimeout(function(){
looper = setInterval(callthis,looptime);
},sleeptime)
}
using like:
begin(doloop);
and pause with
pause(doloop,10000);
You need a callback when using "sleep" functionality. The sleep concept does not exist in JavaScript.
You should not use a busy-loop as you do as that will hold off any other processes as well as JavaScript is single threaded (incl. DOM updates). Use a timer instead but as timers are asynchronous you will have to use the mentioned callback.
It's not so complicated -
Modify the sleep method like this:
function sleep(timeout, callback) {
setTimout(callback, timeout); // or just call this directly...
}
(as you can see it's a bit excess with the wrapper so I would recommend just calling the setTimeout() directly).
Now you can implement your score screen into a function:
function showScores() {
...
}
Then when you want to delay a second before showing the score screen do:
sleep(1000, showScores);
or simply:
setTimeout(showScores, 1000);
Note that the rest of your code will continue after calling this method so make sure all code resides in functions so you can use them as callbacks.
Related
I have created this infinite loop in javascript, in order to run a setTimeout function. The problem is that, by doing this, my page doesn't even load in the first place.
Here is the javascript code:
function blurDiv() {
console.log("here");
rankingList.style.filter="blur(0.7)";
}
function loadContent() {
console.log("loaded");
$( "#ranking-container" ).load("index.php #ranking-list");
rankingList.style.filter="blur(0)";
}
while(true) {
setTimeout(blurDiv, 4000);
setTimeout(loadContent, 5000);
}
I was expecting that the loop would only run another iteration after those 5 seconds.
Use setInterval() instead of while(true){setTimeout()}
function blurDiv() {
console.log("here");
// Other stuff here
}
function loadContent() {
console.log("loaded");
// Other stuff here
}
setInterval(blurDiv, 5000);
setInterval(loadContent, 5000);
Explanation:
setTimeout() is an async function which means JS does not wait for it to complete and continues to run. Therefore, with the loop while(true), it creates two timeout callbacks in every turn which will result in a huge amount (a really huge amount) of timeout callbacks and will never get out of that while(true) loop.
However, by using setInterval() you create a timer that will fire the callback in every cycle (interval).
Harun's answer is sufficient to solve your issue. Additionally, if you want to know more about why you were getting that behaviour, it is due to something called the Event Loop.
Check out this awesome video by Jake Archibald.
You can use setInterval (see other answer) or a callback
function loadIt()
$("#ranking-container").load("index.php #ranking-list",function() {
rankingList.style.filter="blur(0.7)";
setTimeout(loadIt,4000)
});
rankingList.style.filter="blur(0)";
}
loadIt();
I am using a simple function that before it run a slow function, it put a text in the page with : "loading". But this text only show after the function finish.
I did try to add a css too, but it only run after the function finish.
I put a exemple on fiddle and replace my big function with a sleep function. and the result is the same.
http://jsfiddle.net/9nzg9f6L/5/
here the code I am using in the html page:
<div id='msg'>BEGIN</div>
<div style="cursor: pointer; color:red;" id='clickme'>click me!</div>
here is the javascript code:
$("#clickme").click(function(){
// this code only run after the sleep ...
$('#msg').text("PROCESSING");
console.log("text changed");
sleep(5000);
console.log("END function");
});
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {}
}
I cannot modify the sleep(5000) function. It is a placeholder for proprietary and obfuscated function.
even this:
http://jsfiddle.net/9nzg9f6L/7/
does not work.
Take a look at my updated jsFiddle which solves your problem.
http://jsfiddle.net/9nzg9f6L/10/
Updated Code
$("#clickme").click(function(){
//Call slow func using a Self Executing func.
(function(){
//Create the deferred object to use
var defObj1 = $.Deferred();
//Call you slow func
$('#msg').text("PROCESSING");
setTimeout(function(){
sleep(5000)
defObj1.resolve();
}, 500);
return defObj1;
})().done(FunctionTwo);
})
//We call this once the Sleep function is done.
var FunctionTwo = function(){
$('#msg').text("FUNCTION ONE COMPLETED OK..");
};
//Make it slow....
function sleep(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {}
}
Here we make use of a Self-Executing anonymous function and jQuery's Deferred Object with a setTimeout to ensure the slow function executes without halting the entire app. Once done, we can call Function two which in this case simply outputs that the slow function completed.
The problem here is since javascript is single threaded language, browser just didn't have enough time to alter DOM before "slow" function blocks UI completely. To overcome this situation usually you delay slow operation by some very little time, so that DOM update can finish before bad code starts working:
$("#clickme").click(function(){
$('#msg').text("PROCESSING");
$('#msg').addClass("message");
setTimeout(function() {
sleep(5000);
}, 50);
});
Demo: http://jsfiddle.net/9nzg9f6L/6/
But of course if it is possible to make slow code asynchronous it would be the best approach in this case. Blocking UI is never a good UX. Also look into WebWorkers.
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);
Knowing that while Node.js is working asynchronously, writing something like this:
function sleep() {
var stop = new Date().getTime();
while(new Date().getTime < stop + 15000) {
;
}
}
sleep();
console.log("done");
...would call the sleep(), block the server for the duration of the while loop (15secs) and just THEN print "done" to the console. As far as I understand, this is because Node.js is giving JavaScript only access to the main thread, and therefore this kidn of thing would halt further execution.
So I understand the solution to this is to use callbacks:
function sleep(callback) {
var stop = new Date().getTime();
while(new Date().getTime() < stop + 15000) {
;
}
callback();
}
sleep(function() {
console.log("done sleeping");
});
console.log("DONE");
So I thought this would print 'DONE' and after 15 secs. 'done sleeping', since the sleep() function gets called and is handed a pointer to a callback function. While this function is working (the while loop), the last line would be executed (print 'done'). After 15 seconds, when the sleep() function finishes, it calls the given callback function, which then prints 'done sleeping'.
Apparently I understood something wrong here, because both of the above ways block. Can anybody clarify please?
Thanks in advance,
Slagjoeyoco
Javascript and node.js are single threaded, which means a simple while blocks; no requests/events can be processed until the while block is done. Callbacks don't magically solve this problem, they just help pass custom code to a function. Instead, iterate using process.nextTick, which will give you esentially the same results but leaves space for requests and events to be processed as well, ie, it doesn't block:
function doSleep(callback) {
var stop = new Date().getTime();
process.nextTick(function() {
if(new Date().getTime() < stop + 15000) {
//Done, run callback
if(typeof callback == "function") {
callback();
}
} else {
//Not done, keep looping
process.nextTick(arguments.callee);
}
});
}
doSleep(function() {
console.log("done sleeping");
console.log("DONE");
});
You are calling sleep right away, and the new sleep function blocks. It keeps iterating until the condition is met. You should use setTimeout() to avoid blocking:
setTimeout(function () {
console.log('done sleeping');
}, 15000);
Callbacks aren't the same thing as asynchronicity, they're just helpful when you want to get a... callback... from an asynchronous operation. In your case, the method still executes synchronously; Node doesn't just magically detect that there's a callback and long-running operation, and make it return ahead of time.
The real solution is to use setTimeout instead of a busy loop on another thread.
As already mentioned, asynchronous execution should be achieved by setTimeout() rather than while, because while will freeze in one "execution frame".
Also it seems you have syntax error in your example.
This one works fine: http://jsfiddle.net/6TP76/
We want to know if it is possible to have a function using jQuery to inspect a number of elements and, depending on the types assigned to them by one click, perform other functions. Basically, a function that would run forever, while the user does not refresh the page.
The idea is not to depend on events clicks to perform a function, but the classes assigned to a specific element.
For example:
$("td.gantt").each(function() {
if($(this).hasClass("oper")) {
//execute a serie of functions
}
if($(this).hasClass("preop")) {
//execute a serie of functions
}
});
The above is executed once, and we need to run all the time.
// define a function...
function ganttEach() {
$("td.gantt").each(function() {
// ...
});
}
// ...repeat it once every second
window.setInterval(ganttEach, 1000);
You can't "let it run all the time" (like, in a while(true) loop) because JavaScript is single-threaded and blocking the thread means your other code will never run. setInterval() makes sure there are necessary "gaps" for other code to execute.
setInterval() returns an ID that you can store in a variable and feed to clearInterval() at some point to make it stop again.
If you want to make sure that every new iteration of your function starts only after the previous one has really finished, use setTimeout() instead:
// define a self-repeating function...
function ganttEach() {
$("td.gantt").each(function() {
// ...
});
window.setTimeout(ganttEach, 1000); // calls itself again in one second
}
// ...initiate self-repeating function
ganttEach();
You should probably include some way to stop the endless repetition here as well, like introducing a flag that's checked before the setTimeout() call.
You can run your check every few milliseconds, say 50ms, using setInterval
window.setInterval (function () {
// do checks here
}, 50);
You might end up using a lot of CPU power if your checks are too frequent, or too complicated.
It is possible, with setInterval. My advice would be to select the element outside of the repeating function so as to minimize the overhead.
An infinite loop would lock the browser UI, as it is a single threaded environment. Set interval, however let you add actions to the UI stack which will be executed after a given period of time. You can specify this period in the second parameter of setInterval.
// select the element outside
// to minimize overhead
$gantt = $("td.gantt");
// define a repeating action
setInterval(function() {
$gantt.each(function() {
if($(this).hasClass("oper")) {
//execute a serie of functions
}
if($(this).hasClass("preop")) {
//execute a serie of functions
}
});
}, 100); // repeat interval: 100ms
I am not sure exactly what you are trying to do, but have you tried setInterval? It will keep running if that is what you really want.
window.setInterval(function () {
// add your jQuery here
}, 100);