JavaScript - 'this' inside setTimeout and requestAnimationFrame

343 views Asked by At

My question is related to the following:

setTimeout() inside JavaScript Class using “this”

calling a function inside setTimeout and inside a function

I'm trying to implement a simple animation loop. The draw function is a member function of a state object. I'm having problems getting 'this' to work within the setTimeout and requestAnimationFrame.

I have the following code:

ANIM.State.prototype = {
    constructor: ANIM.State,
    play: function(){
        if(!this.paused){
            var that = this;
            setTimeout(function(){
                requestAnimationFrame(that.play);
                that.setFrameNum(that.currentFrame + 1); //draw code is in here
            }, 1000 / 24);
        }
    }
};

However, when I call play(), it runs twice and stops.

Is there a better way to do this? I'd really like to keep this function as a class function, and not a global one, if possible.

1

There are 1 answers

0
jfriend00 On BEST ANSWER

You can solve your issue with .bind() like this:

requestAnimationFrame(that.play.bind(that));

The problem is all that is passed to requestAnimationFrame() is a reference to the .play method and it is then executed as a normal function call so this inside it will be wrong and will not point to your object. This is a common problem when passing a method as a callback where you want it to be called as obj.method().

There are numerous possible work-arounds, but the easiest in modern browsers is to use .bind() as I've shown above. This actually creates a small stub function that then calls that.play() rather than just play() so that the object reference is used as you need and it's that stub function that is passed to requestAnimationFrame().

You could also do it like this (creating your own stub function), though .bind() seems cleaner to me:

requestAnimationFrame(function() {
    that.play();
});