I'm writing a "Game of Life" in javascript. I have all the logic done in a function called doGeneration(). I can repeatedly call this from the console and everything goes as planned, however, if I put it in a while loop the execution blocks the UI and I just see the end result (eventually).
while (existence) {
doGeneration();
}
If I add a setTimeout(), even with a generation limit of say 15, the browser actually crashes (Canary, Chrome).
while (existence) {
setTimeout(function() {
doGeneration();
},100);
}
How can I call doGeneration() once every second or so without blocking the DOM/UI?
You want setInterval
var intervalId = setInterval(function() {
doGeneration();
}, 1000);
// call this to stop it
clearInterval(intervalId);
I would use requestAnimationFrame(doGeneration). The idea of this function is to let the browser decide at what interval the game logic or animation is executed. This comes with potential benefits.
https://hacks.mozilla.org/2011/08/animating-with-javascript-from-setinterval-to-requestanimationframe/
Rather than using setINterval or setTimeout and assume some random time interval will be enough for the UI to update you shoul/could make the doGeneration smart enough to call itself after dom was updated and if the condition of existence is satisfied.
Related
I want to have code that simply will count up by one every second or so. However, I also want to be able to run other code alongside it.
Example:
while(true){
Number + 1 + OtherNumber = Number
}
And also be able to run this at the same time:
function onButtonPress() {
OtherNumber++
}
Note: I do not want to increment otherNumber at an interval, but rather on the press of a button.
You can use setInterval:
var intervalId = setInterval(function() {
OtherNumber++;
}, 1000);
It will increase OtherNumber by one approximately every second.
setInterval returns ID of interval, which can be used to stop it:
clearInterval(intervalId);
Demo snippet:
document.body.innerHTML += "Start<br/>";
setInterval(function() {
document.body.innerHTML += "Interval step<br/>";
}, 1000);
document.body.innerHTML += "Look! Code is completed before interval step<br/>";
If you want to run code as two separate threads you will have to use web Workers as Javascript is single threaded and can not run more than one function at a time.
If you create a function
function workForever(){
while(true){
.. do work
}
}
You will completely block all code, no events will get called, no other javascript will be executed. Most browsers will throw up a dialog reporting that a function is taking a long time do you want to kill the page. But your code is stuck in that loop and can only be exited from within the loop itself.
WebWorkers are a good solution to multitasking in the Javascript environment, but you still need to provide some non execution time to allow the webworkers to communicate. The while(true) will block all communication with the workers, in effect making them useless.
SetInterval, setTimeout, requestAnimationFrame will also be blocked. Javascript unfortunately is single threaded and will never be able to run two functions at the same time.
I have a very heavy graphical issue to perform, and I need to be able to show an onscreen progress bar and also prevent the browser from getting "freeze".
I understand that tight looping is blocking the UI, and JavaScript is single threaded, so I using setTimeout in order to perform some graphical testing as follow:
function FG_ShowHM(y) {
for(var x=0 ; x<100 ; x++) {
if(FG_TreeH[y*100+x]=="") {
FG_hmctx.fillStyle = "rgba(255,255,255,1)";
}
else {
var col=DegToCol(FG_min,FG_max,FG_TreeH[y*100+x]);
FG_hmctx.fillStyle = "rgba("+col.r+","+col.g+",0,1)";
}
FG_hmctx.fillRect(x*3,y*3,3,3);
}
ProgBT+=0.5;
y++;
if(y<100) {
window.setTimeout(FG_ShowHM(y),100); // move on
}
else {
XPW();
}
}
And a call to that function from within another function:
window.setTimeout(FG_ShowHM(0));
NOTE: PW() is just a shortcut to jQuery functions that creating the "please wait evement, and XPW is just a shortcut to remove the "please wait" window.
For some reason the UI is still stack without possibility to show any progress, and more than that, after few seconds the browser get completely "freeze"...
I have tried many many ways to solve this issue, but without success.... I would like to know what is the best way to show up progress in such a long operation, or at least prevent the browser from getting "freeze".
Thanks in advance.
The problem is the way you use window.setTimeout. As a first argument it expects a function and a number as a 2nd. When you do window.setTimeout(FG_ShowHM(y),100); you actually don't pass a function as a parameter but execute it and the result of the execution pass to window.setTimeout. As a result - you have an infinite recursion.
To fix it - correct the way of calling window.setTimeout to
window.setTimeout(function() { FG_ShowHM(y) }, 100);
Note: there are a lot of places in your code of such window.setTimeout usage. So be attentive.
Read more about window.setTimeout here.
It seems that everyone has a few problems with clearInterval. I have built a slider that allows people to hover a click on arrows. The banner also rotates ever few seconds. I want to be able to have the auto-rotate turn off after someone clicks on one of the arrows.
Here's my code:
$(function(){
var intvl = 0;
intvl = setInterval(heroTransitionNext, 2000);
$('.rightArrow').click(function(){
window.clearInterval(intvl);
});
});
EDIT:
Here is the function it is calling:
function heroTransitionNext() {
$('.HP-hero li').filter(':visible').fadeOut('normal', function () {
if ($(this).next().length != 0) {
activeZone = parseInt(activeZone) + 1;
$(this).next().fadeIn('normal', heroNavHighlight(activeZone));
} else {
activeZone = 1;
$('.HP-hero li:first-child').fadeIn('normal', heroNavHighlight(activeZone));
}
$(this).hide();
});
};
To stop the animation you can use jquery's .stop() but not sure whether it'll solve the problem or not that you are facing (didn't visualize) but you can give it a try
$('.HP-hero li').stop(1,1); // or try $('.HP-hero li').stop()
window.clearInterval(intvl);
As say2joe said that clearInterval will just stop the function from invoking next time but it won't clear the current queue (he is right) so in that case stop could be used.
About Stop.
Depending on how much work your heroTransitionNext function is doing, it may still be executing even though the interval is cleared -- in other words, clearing the interval will stop the function from being invoked -- but, any instance of the function(s) executing in memory will continue to execute until finished.
To be more clear, here's a use case (you can check this out yourself by using a profiler in Firebug or Developer Tools):
heroTransitionNext execution time is 2.1 seconds.
clearInterval is invoked 6.1 seconds after setInterval is invoked.
At 6.1 seconds, heroTransitionNext has been invoked four times. The first three executions have completed, however, the fourth will not complete until it finishes executing (at 8.1 seconds since setInterval was called). Note: In this use case, each successive invokation will execute while the last invokation's execution is still continuing (for 100 more ms) -- in other words, you'll have execution overlap from 2 to 2.1, 4 to 4.1, and 6 to 6.1 second intervals.
If the function takes longer to execute than the interval set, use a recursive function with setTimeout(). The following link will give you a good example.
Also, a good reference for explanation is https://developer.mozilla.org/en/DOM/window.setInterval.
what i need is a for or while loop that will re run the code every second
ive tried sleep() but i dont think it is working or i have got it right
Do not try to use a for or while loop for such timed operations. You'll have a hard time with reliable or accurate timing and usually end up railing the CPU, making the computer sluggish.
JavaScript provides the setInterval() function for these kinds of tasks. Also note that Greasemonkey has some caveats about how to use setInterval() and setTimeout().
So the code you want is like:
var timerVar = setInterval (function() {DoMeEverySecond (); }, 1000);
function DoMeEverySecond ()
{
//--- Your code here.
}
//--- When ready to stop the timer, run this code:
clearInterval (timerVar);
timerVar = "";
try
// where yourfunction is a method that contains your loop logic
setTimeout(yourfunction, 1000);
This will invoke the function every 1000 milliseconds without having to embed it into a while or for loop.
put it into your body onload or similar event
I am not too familiar with the specifics of every javascript implementation on each browser. I do know however that using setTimeout, the method passed in gets called on a separate thread. So would using a setTimeout recursively inside of a method cause its stack to grow indefinitely until it causes a Stack Overflow? Or would it create a separate callstack and destroy the current frame once it goes out of focus? Here is the code that I'm wondering about.
function pollServer()
{
$.getJSON("poll.php", {}, function(data){
window.setTimeout(pollServer, 1000);
});
}
window.setTimeout(pollServer, 0);
I want to poll the server every second or so, but do not want to waste CPU cycles with a 'blocking loop' - also I do not want to set a timelimit on how long a user can access a page either before their browser dies.
EDIT
Using firebug, I set a few breakpoints and by viewing the "Script -> Stack" panel saw that the call stack is literally just "pollServer" and it doesn't grow per call. This is good - however, do any other implementations of JS act differently?
I am not sure if it would create a stack overflow, but I suggest you use setInterval if the period is constant.
This is how prototype implements its PeriodicalExecuter.
// Taken from Prototype (www.prototypejs.org)
var PeriodicalExecuter = Class.create({
initialize: function(callback, frequency) {
this.callback = callback;
this.frequency = frequency;
this.currentlyExecuting = false;
this.registerCallback();
},
registerCallback: function() {
this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
},
execute: function() {
this.callback(this);
},
stop: function() {
if (!this.timer) return;
clearInterval(this.timer);
this.timer = null;
},
onTimerEvent: function() {
if (!this.currentlyExecuting) {
try {
this.currentlyExecuting = true;
this.execute();
} finally {
this.currentlyExecuting = false;
}
}
}
});
setTimeout executes sometime later in the future in the event pump loop. Functions passed to setTimeout are not continuations.
If you stop and think about it, what useful purpose or evidencec is there that the call stack is shared by the timeout function.
If they were shared what stack would be shared from the setter to the timeout function ?
Given the setter can do a few returns and pop some frames - what would be passed ?
Does the timeout function block the original thread ?
Does the statement after the setTimeout function execute after the timeout executes ?
Once you answer those questions it clearly becomes evident the answerr is NO.
setTimeout does not grow the callstack, because it returns immediately. As for whether your code will run indefinitely in any browser, I'm not sure, but it seems likely.
take a look at the jQuery "SmartUpdater" plugin.
http://plugins.jquery.com/project/smartupdater
Following features are available:
stop() - to stop updating.
restart() - to start updating after pause with resetting time interval to minTimeout.
continue() - to start updating after pause without resetting time interval.
status attribute - shows current status ( running | stopping | undefined )
updates only if new data is different from the old one.
multiplies time interval each time when data is not changed.
handle ajax failures by stopping to request data after "maxFailedRequests".