jsperf testing setInterval() vs requestAnimationFrame() - javascript

Can someone explain why turnEvenOld(250, 250)(0.089ms) runs much much more faster than turnEvent(250, 250)(0.447ms)?
I thought using requestAnimationFrame() was a lot faster and cheaper to run than setInterval()?
setInterval():
var turnEventOLD = function turnEvent(AnX, AnY) {
----VARIABLES----
temp = setInterval(myAnimation1, 1000/60);
function myAnimation1() {
----DRAWINGCANVAS------
-----
----CONDITIONS--------
if (one301 && one401) {
clearInterval(temp);
}
}
}
requestAnimationFrame():
var turnEvent = function turnEvent(AnX, AnY) {
----VARIABLES-----
function render() {
----DRAWING CANVAS-----
------
----CONDITIONS---------
if (one301 && one401) {
---stop requestAnimation--
}
}
(function animloop(){
----CONDTION-----
requestAnimationFrame(animloop);
render();
})();
}

RequestAnimation frame is not necessarily "faster" than setInterval. It actually does something different.
setInterval will wait a given number of milliseconds while requestAnimationFrame will wait until the page is ready to repaint. Depending on the time in your setInterval call, the time setInterval waits could be shorter or longer than the time until the next repaint.
It is better to use requestAnimationFrame for animations so you're sure you change the visual elements before the next repaint instead of being potentially out of synch with the page repaints.

Related

Changing the period in the setInterval() method while running

How to change the period (timer) in setInterval() method without using clearInterval() of that method(Id)?
I want to make the method have an initial fixed speed and slow down over time and with the help of the setTimeout() method to finish in ten seconds for example?
If I could get some examples I would be very grateful :)
I think an interval is the wrong thing to use. You would be better off using setTimeout and call the next timeout based on the new waiting time you want.
function runIt(myFunc) {
let waitFor = 3000;
function executeIt () {
myFunc();
waitFor = waitFor - 250;
if (waitFor>=0) {
next();
}
}
function next() {
window.setTimeout(executeIt, waitFor);
}
next();
}
runIt(function (){ console.log(Date.now())})

jquery setTimeout too much recursion

I have read from multiple places that setTimeout() is preferable to setInterval() when setting something up to basically run forever. The code below works fine but after about an hour of running Firefox (38.0.1) throws an error of too much recursion.
Essentially I have it grabbing a very small amount of text from counts.php and updating a table with that information. The whole call and return takes about 50ms according to the inspectors. I'm trying to have it do this every x seconds as directed by t.
I suspect if I switch to setInterval() this would probably work, but I wasn't sure what the current state of the setTimeout() vs setInterval() mindset is as everything I've been finding is about 3-5 years old.
$(document).ready(function() {
t = 3000;
$.ajaxSetup({cache: false});
function countsTimer(t) {
setTimeout(function () {
$.getJSON("counts.php", function (r) {
$(".count").each(function(i,v) {
if ($(this).html() != r[i]) {
$(this).fadeOut(function () {
$(this)
.css("color", ($(this).html() < r[i]) ? "green" : "red")
.html(r[i])
.fadeIn()
.animate({color: '#585858'}, 10000);
})
};
});
t = $(".selected").html().slice(0,-1) * ($(".selected").html().slice(-1) == "s" ? 1000 : 60000);
countsTimer(t);
});
}, t);
};
countsTimer(t);
});
Update: This issue was resolved by adding the .stop(true, true) before the .fadeOut() animation. This issue only occurred in Firefox as testing in other browsers didn't cause any issues. I have marked the answer as correct in spite of it not being the solution in this particular case but rather it offers a good explanation in a more general sense.
You should indeed switch to setInterval() in this case. The problem with setInterval() is that you either have to keep a reference if you ever want to clear the timeout and in case the operation (possibly) takes longer to perform than the timeout itself the operation could be running twice.
For example if you have a function running every 1s using setInterval, however the function itself takes 2s to complete due to a slow XHR request, that function will be running twice at the same time at some point. This is often undesirable. By using setTimout and calling that at the end of the original function the function never overlaps and the timeout you set is always the time between two function calls.
However, in your case you have a long-running application it seems, because your function runs every 3 seconds, the function call stack will increase by one every three seconds. This cannot be avoided unless you break this recursion loop. For example, you could only do the request when receiving a browser event like click on the document and checking for the time.
(function()
{
var lastCheck = Date.now(), alreadyRunning = false;
document.addEventListener
(
"click",
function()
{
if(!alreadyRunning && Date.now() - lastCheck > 3000)
{
alreadyRunning = true;
/* Do your request here! */
//Code below should run after your request has finished
lastCheck = Date.now();
alreadyRunning = false;
}
}
)
}());
This doesn't have the drawback setInterval does, because you always check if the code is already running, however the check only runs when receiving a browser event. (Which is normally not a problem.) And this method causes a lot more boilerplate.
So if you're sure the XHR request won't take longer than 3s to complete, just use setInterval().
Edit: Answer above is wrong in some aspects
As pointed out in the comments, setTimeout() does indeed not increase the call stack size, since it returns before the function in the timeout is called. Also the function in the question does not contain any specific recursion. I'll keep this answer because part of the question are about setTimeout() vs setInterval(). However, the problem causing the recursion error will probably be in some other piece of code since there is not function calling itself, directly or indirectly, anywhere in the sample code.

Is it a good idea to use requestAnimationFrame within a debounce function?

This is a check on my understanding of requestAnimationFrame. I have a need for a debounce function, as I'm doing some DOM interaction every time the window is resized and I don't want to overload the browser. A typical debounce function will only call the passed function once per interval; the interval is usually the second argument. I'm assuming that for a lot of UI work, the optimum interval is the shortest amount of time that doesn't overload the browser. It seems to me that that's exactly what requestAnimationFrame would do:
var debounce = function (func, execAsap) {
var timeout;
return function debounced () {
var obj = this, args = arguments;
function delayed () {
if (!execAsap)
func.apply(obj, args);
timeout = null;
};
if (timeout)
cancelAnimationFrame(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = requestAnimationFrame(delayed);
};
}
The above code is a direct rip-off from the above debounce link, but with requestAnimationFrame used instead of setTimeout. In my understanding, this will queue up the passed-in function as soon as possible, but any calls coming in faster than the browser can handle will get dropped. This should produce the smoothest possible interaction. Am I on the right track? Or am I misunderstanding requestAnimationFrame?
(Of course this only works on modern browsers, but there are easy polyfills for requestAnimationFrame that just fall back to setTimeout.)
This will work.
It has a caveat that may or may not be important to you:
If the page is not currently visible, animations on that page can be throttled heavily so that they do not update often and thus consume little CPU power.
So if you for some reason care about this for the function you are debouncing, you are better off using setTimeout(fn, 0)
Otherwise if you are using this for animations, this is the intended usage of requestAnimationFrame

Javascript code execution pausing issue

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.

How to suspend JavaScript to allow render

I have a little script that runs a simulation, of which I want to render the results 'live':
for ( i < simulation steps ) {
do_simulation();
render_with_flot();
}
I noticed that the plot only gets rendered after the last step.
Is there a way to 'suspend' javascript somehow to allow the rendering to run after each iteration?
Or is there a way to make flot run synchronously?
Or do I need to set my own timeouts for each iteration of the for-loop? This seems like kind of a hassle.
Depends how fast it needs to run, but the best way would be to use SetInterval
Pseudocode / hand-written-javascript-that-probably-doesnt-run:
var PerformedSteps;
var Interval;
PerformedSteps = 0;
Interval = setInterval(work, 1000/60); //60 times/second
function work()
{
PerformedSteps++;
if (PerformedSteps == simulation_steps)
{
clearInterval(Interval);
return;
}
do_simulation();
render_with_flot();
}
As an alternative to #PhonicUK's solution, you could do a setTimeout() at the end of work() to schedule the next call to work(), giving the rendering a chance to happen & not tying yourself to any particular refresh rate.

Categories