So I have written a working application (actually half of it) with requestAnimationFrame. Before the project gets too complex I'm rushing to rewrite it in an object-oriented style so we can implement plugins better (and also fix modules without changing the whole app). In fact the first version of the app was really messed up and made up from a lot of test code.

So I have the following:

Aventura.prototype.update = function() {
  var av = this;
  requestAnimationFrame(av.update);

  /* ... frame code ... */
};

And I get "Uncaught TypeError: Type error " in the console log, right in the requestAnimationFrame line. I know my browser has a proper requestAnimationFrame implementation since I used the messed up version of my app perfectly well.

I've reached the conclusion that it raises an exception because I'm calling a method that is a member of the caller's own parent object (I know it's exactly the same method, but the problem clearly isn't on self-calling since that's what RAF is supposed to do). Any clues of what's wrong?

有帮助吗?

解决方案

This has nothing to do with requestAnimationFrame. It is a basic JavaScript issue related to passing functions in general, and the meaning of this.

People tend to think that a function-valued property inside an object, such as myFn in the below

var myObj = {
    myFn: function() {console.log(this);}
};

somehow has myObj "baked in" as this. Wrong. this is assigned only at the time the function is called. If I say myObj.myFn(), this becomes myObj, but I could just as easily say myObj.myFn.call(otherObj) to have this be something else.

This becomes important when passing functions around as parameters to setTimeout, promises, or requestAnimationFrame. Just passing myObj.myFn passes the function, but it has no associated this. requestAnimationFrame has no idea where this function came from and what this to call it with, so it calls it with a this of window, or null, or 0, or undefined, or who knows what. This causes the error.

The simplest way to fix the problem is to simply say

requestAnimationFrame(function() {av.update(); });

Now update is called with the correct this.

A more sophisticated, equivalent way, would be

requestAnimationFrame(av.update.bind(av));

Other note

I don't think the way you're passing the function itself to requestAnimationFrame is going to work well. You're essentially setting up a chain of recursive calls, and eventually the stack will overflow. You need to separate the logic to be executed on the requestAnimationFrame callback from the logic to request the frame.

其他提示

I've ended up finding the answer on another question here. I don't think it classifies as a duplicate though, since both questions were asked in different ways and someone could find one but not the other question (I myself seeked for a similar problem all over the web and didn't ever run into this potential duplicate).

How to call requestAnimFrame on an object method?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top