48 votes

requestAnimationFrame avec ce mot-clé

J'utilise webkitRequestAnimationFrame mais j'ai du mal à l'utiliser à l'intérieur d'un objet. Si je passe le this mot-clé qu'il utilisera window et je ne trouve pas de moyen pour qu'il utilise l'objet spécifié à la place.

Exemple :

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

  window.webkitRequestAnimationFrame(this.draw);
};

J'ai également essayé, mais sans succès :

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);
};

97voto

Matt Ball Points 165937

J'essaie de passer display.draw qui est la fonction dans laquelle réside webkitRequestAnimationFram.

webkitRequestAnimationFrame appellera vraisemblablement la fonction que vous lui aurez passée, quelque chose comme ceci :

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

À ce stade, vous avez dissocié (détaché) le draw de son contexte d'invocation. Vous devez lier la fonction ( draw ) à son contexte (l'instance de Display ).

Vous pouvez utiliser Function.bind mais ceci nécessite le support de JavaScript 1.8 (ou utilisez simplement le patch recommandé).

Display.prototype.draw = function()
{
    // snip...

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

26voto

James World Points 9394

Maintenant que l'ES6/2015 est là, si vous utilisez un transpilateur, une fonction flèche a une valeur lexicale. this liant ainsi au lieu de :

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

vous pouvez faire :

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

qui est un peu plus propre.

Je l'ai utilisé efficacement avec Typescript transposé en ES5.

6voto

Pawel Points 204

Je ne peux pas garantir que c'est une bonne idée et que j'ai raison, mais exécuter .bind sur chaque requestAnimationFrame signifie créer une nouvelle fonction à chaque itération. Cela ne me semble pas correct.

C'est pourquoi, dans mon projet, j'ai mis en cache la fonction liée pour éviter cet anti-modèle.

Un exemple simple :

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

Si vous avez un projet plus complexe avec un héritage de prototype, vous pouvez toujours créer une fonction en cache avec "this" lié au constructeur de l'objet.

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();

Qu'en pensez-vous ? http://jsfiddle.net/3t9pboe8/ (regardez dans la console)

3voto

bogdan Points 374

Que pensez-vous de ça ?

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) );
};

...en supposant que vous utilisez jquery

1voto

Tomáš Points 760

Vous ne devez pas utiliser "ceci". Restez simple.

var game = {
      canvas:null,
      context:null,

    init:function(){
            // init canvas, context, etc
    },      

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X