Jump to content

Simple Animation Loop Issue w/ Firefox (jfiddle example)


astralaaron

Recommended Posts

If you view the jFiddle example in chrome, and view the Javascript console, you will see the frame rate output is constant and smooth. Then if you switch over to Firefox > Firebug console and run the jFiddle again, you will see it goes smooth except for every so often it pauses for a moment. I've literally been unsuccessful for over a year to get a smooth loop going in all browsers. I'm hoping someone can shed some light on whats going on with this small example! I appreciate everyone who reads this and takes a look a the problem..:

 

http://jsfiddle.net/aLv3vsv8/

Link to comment
Share on other sites

Well, there are two things that are probably interfering. One is that the firebug console takes up resources, slowing down Javascript, the other thing is that the pauses are probably caused by the garbage collector. My computer is pretty fast, so that's probably why I haven't experienced this problem in Firefox.

 

Since you're using requestAnimationFrame, I recommend you take the timestamp that's automatically passed to the function which has microsecond precision.

  'loop' : function(microtime) {            if (e.animate.stop) return;            requestAnimationFrame(e.animate.loop);            e.animate.time.elapsed = microtime - e.animate.time.then;                if (e.animate.time.elapsed > e.animate.frame.rate) {            e.animate.time.then = microtime;            e.animate.showFPS();            }        },
Link to comment
Share on other sites

Since you're using requestAnimationFrame, I recommend you take the timestamp that's automatically passed to the function which has microsecond precision.

I had no idea a timestamp was automatically passed in! This does seem to improve the performance slightly..however, now in the start function the frame rate doesn't calculate properly and I am not quite sure what the math needs to be to fix it. I am referring to this line in the 'start' function:

e.animate.frame.rate = 1000 / e.animate.frame.fps;

Changing that 1000 down to 100 or so makes it pretty smooth..I read that the requestAnimationFrame timestamp is equal to 10 miliseconds. I'm interested to see it when the frame rate is calculated properly, but it does seem to still have an occasional stutter. I do think you are right about the garbage collector, after reading around I am pretty sure on my main script that is having this problem I did a poor job of it.

 

I have a couple questions about that.. first, if I have a function like the following, do I need to set the variables to null after using them?:

function a() {var x = 'something';var y = 'something else';var z = x + " " + y;}

Also, if I have a function that is a member of another function like the following, and I only use it once, should I be deleting it? (delete b.C)

function B() {var b = this;this.C = function() {}}

EDIT/question:

 

Another indication (i think) that it is poor garbage collection is that if I add multiple instances of this my canvas/script, they all stutter at the same exact times, and for the same duration. It seems that javascript entirely locks up. Would you say that is an indication that it has nothing to do with my animation loop in the first place?

Edited by astralaaron
Link to comment
Share on other sites

Continuous Time

 

There's one thing you should know about requestAnimationFrame: It doesn't have a fixed interval. It runs as soon as it is able to, so what you should do is make your animation a function of time. Forget the concept of frames and framerates and think in continuous time.

 

I believe the stutters in your animation come from trying to make a fixed framerate, because occasionally it will have to go through two cycles of requestAnimationFrame to catch up to your frame, which may take longer than one frame.

 

Here's an example of making something move 100 pixels per second (0.1 pixels per millisecond) using continuous time:

var previousTime;var speed = 0.1; // 0.1 pixels per millisecondvar position = { x : 0, y : 0};function move(time) {  if(!previousTime) previousTime = time;  var elapsedTime = time - previousTime;  var step = elapsedTime * speed;  pos.x += step;  previousTime = time;}

Garbage Collection

 

As for the garbage collection problem, yes it possibly is the garbage collection, but how efficiently the garbage collector works depends entirely on your code. Try not to create objects inside functions, this includes dates and arrays. Also try to reduce the amount of HTML elements you're dynamically creating and be sure that after they're created you always keep a reference to them.

Link to comment
Share on other sites

I am working on giving this example a try right now, but I have a question now about how to structure my script. I didn't realize putting objects inside of functions was really bad for garbage collection. Since I had read that Javascript can be used like an OOP language, I've been writing all of my scripts like that because it helps me organize and work with them. For example:

 

I am always writing scripts like this because they end up getting big and I find that I can stay organized and have scope to everything easily:

function SomeScript() {    var s = this;    this.animate = {        'vars': {            'x' : 0,            'y' : 0,            //etc..        },        'start' : function() {            console.log('starting x/y = ' + s.animate.vars.x + '/' + s.animate.vars.y);            s.animate.stop();        },         'stop': function() {            console.log('stopping');        }    };}var x = new SomeScript();x.animate.start();

Would you recommend I ditch the above style and try to write things like this?:

var x = 0;var y = 0;function stop() {     console.log('stopping');}function start() { console.log('starting x/y = ' + x + '/' + y);     stop();}start();
Edited by astralaaron
Link to comment
Share on other sites

No, don't ditch it. That style is fine because the object is not being destroyed when the function ends.

 

This is an example that would be a problem with the garbage collector:

function doSomething(a, B) {  var position = { x: a, y: b };  position.x++;  position.y++;  return [position.x, position.y];}

The function is creating an object position in the function which is immediately destroyed when the function ends. Then it's returning an array whose value will be used and then the array will be destroyed too, so that's two things for the garbage collector to pick up every time the function runs.

 

In your JSFiddle example I don't see anything in particular that would make the garbage collector do a lot of work. The only thing I see there is Date.now(). I'm not entirely sure if internally it generates a Date object or not but it probably doesn't.

 

If the problem is only happening on your actual page then you should look at some of the code that's not in the JSFiddle example.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...