2

This following is causing an error (FF, Chrome, and ?):

JSFiddle recreation

Engine.prototype.requestAnimationFrame = window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        function(/* function */ callback, /* DOMElement */ element){
            window.setTimeout(callback, 1000 / 60);
};

And the full context is:

var Engine = function(model) {

        this.model = model;
    };

    Engine.prototype.start = function() {
        console.log("ready")
        this.requestAnimationFrame(function() {
            console.log("done");
        });
    };

    Engine.prototype.updateUi = function() {

        console.log("update ui");
        this.requestAnimationFrame(this.updateUi);
    };

    Engine.prototype.logRAF = function() {
        console.log(window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame);
        return this;
    };

    Engine.prototype.requestAnimationFrame = window.requestAnimationFrame ||
            window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame ||
            window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function(/* function */ callback, /* DOMElement */ element){
                window.setTimeout(callback, 1000 / 60);
            };

var engine = new Engine();
engine.logRAF().start();

The error is the following in FF - mozRequestAnimationFrame(): NS_ERROR_XPC_BAD_OP_ON_WN_PROTO: Illegal operation on WrappedNative prototype object

The error is the following in Chrome - webkitRequestAnimationFrame(): Uncaught TypeError: Illegal invocation

on the line:

this.requestAnimationFrame...

The log reads prints out "ready", but not "done"

If I use just a function instead of the native RAF methods, it works ("done" is logged):

JSFiddle recreation

What is going on with the RequestAnimationFrames?

Community
  • 1
  • 1
Peter Ajtai
  • 54,199
  • 12
  • 118
  • 138

2 Answers2

6

When you're invoking window's function, the context(this) must be the window, not your object( Engine's instance ). bind will help you to resolve that problem:

Engine.prototype.requestAnimationFrame = 
        (window.requestAnimationFrame && window.requestAnimationFrame.bind(window)) ||
        (window.webkitRequestAnimationFrame && window.webkitRequestAnimationFrame.bind(window)) ||
        //etc...

live demo

Engineer
  • 43,887
  • 11
  • 83
  • 90
  • @PeterAjtai Glad that helped. – Engineer Dec 28 '12 at 11:20
  • You can also use `(window.a || window.b || ...).bind(window)`. – pimvdb Dec 28 '12 at 11:20
  • @pimvdb - assuming one of the "window" RAF function methods is available. If it falls back to the regular function that will through an error.... but yes, there are some shortcuts to be made. – Peter Ajtai Dec 28 '12 at 11:28
  • I don't think it will cause an error - the fallback function doesn't use `this`, so using `.bind` is a no-op for that one. – pimvdb Dec 28 '12 at 11:30
  • @pimvdb undefined.bind(window) is an error http://jsfiddle.net/pajtai/RL24r/ - so it just has to be wrapped a little better: – Peter Ajtai Dec 28 '12 at 11:35
2

requestAnimationFrame should be called in the context of the window : this.requestAnimationFrame.call(window, ...); as mentioned here: "Uncaught TypeError: Illegal invocation" in Chrome

Community
  • 1
  • 1
Ivan Nikolchov
  • 1,436
  • 1
  • 26
  • 37