requestAnimationFrame with this keyword

JavascriptObjectAnimationThis

Javascript Problem Overview


I'm using webkitRequestAnimationFrame but I'm having trouble using it inside of an object. If I pass the this keyword it will use window and I can't find a way for it to use the specified object instead.

Example:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame(this.draw);
};

I have also tried this but to no avail:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  var draw = this.draw;
  window.webkitRequestAnimationFrame(draw);
};

Javascript Solutions


Solution 1 - Javascript

> I'm trying to pass display.draw which is the function in which webkitRequestAnimationFram resides.

webkitRequestAnimationFrame will presumably call the function you pass in, something like this:

function webkitRequestAnimationFrame(callback)
{
    // stuff...
    callback();
    // other stuff...
}

At this point, you have dissociated (detached) the draw function from its invocation context. You need to bind the function (draw) to its context (the instance of Display).

You can use Function.bind, but this requires JavaScript 1.8 support (or just use the recommended patch).

Display.prototype.draw = function()
{
    // snip...
    
    window.webkitRequestAnimationFrame(this.draw.bind(this));
};

Solution 2 - Javascript

Now that ES6/2015 is here, if you are using a transpiler then an arrow function has lexical this binding so instead of:

window.webkitRequestAnimationFrame(this.draw.bind(this));

you can do:

window.webkitRequestAnimationFrame(() => this.draw());

which is a bit cleaner.

I've used this effectively with Typescript transpiling to ES5.

Solution 3 - Javascript

I can't guarantee that this is a good idea and that I'm right, but running .bind on every requestAnimationFrame means creating a new function on every iteration. It just doesn't sound right to me.

That's why in my project I cached the bound function to avoid the anti-pattern.

Simple example:

var Game = function () {
    this.counter = 0;
    this.loop = function () {
        console.log(this.counter++); 
        requestAnimationFrame(this.loop);
    }.bind(this);
    this.loop();
}
var gameOne = new Game();

If you have a more complex project with prototype inheritance you can still create a cached function with "this" bound in object's constructor

var Game = function () {
    this.counter = 0;
    this.loopBound = this.loop.bind(this);
    this.loopBound();
}
Game.prototype.loop = function () {
    console.log(this.counter++); 
    requestAnimationFrame(this.loopBound);
}
var gameOne = new Game();

Thoughts? http://jsfiddle.net/3t9pboe8/ (look in the console)

Solution 4 - Javascript

how about this:

Display.prototype.draw = function(){
  this.cxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
  //Animation stuff here.

  window.webkitRequestAnimationFrame( $.proxy(function() {this.draw()}, this) );
};

...assuming you use jquery

Solution 5 - Javascript

you have not to use "this". Keep it simple.

var game = {
      canvas:null,
      context:null,
    
	init:function(){
       		// init canvas, context, etc
	},		

	update:function(){
		//do something
		game.render();			  			  
		requestAnimationFrame(game.update, game.canvas);		
	},            
};

Solution 6 - Javascript

Beside bind method, and arrow function solution (offered by Jamaes World's answer), Another (rather old) work around could be:

var self = this
window.webkitRequestAnimationFrame(
    function() {
        self.draw()
    }
);

Solution 7 - Javascript

And also you might want to use requestAnimationFrame shim to make it work on all browsers https://github.com/kof/animation-frame

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRyanView Question on Stackoverflow
Solution 1 - JavascriptMatt BallView Answer on Stackoverflow
Solution 2 - JavascriptJames WorldView Answer on Stackoverflow
Solution 3 - JavascriptPawelView Answer on Stackoverflow
Solution 4 - JavascriptbogdanView Answer on Stackoverflow
Solution 5 - JavascriptTomášView Answer on Stackoverflow
Solution 6 - JavascriptMortezaEView Answer on Stackoverflow
Solution 7 - JavascriptOleg IsonenView Answer on Stackoverflow