When I use requestAnimationFrame
to do some native supported animation with below code:
var support = {
animationFrame: window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
};
support.animationFrame(function() {}); //error
support.animationFrame.call(window, function() {}); //right
Directly calling the support.animationFrame
will give...
Uncaught TypeError: Illegal invocation
in Chrome. Why?
When you execute a method (i.e. function assigned to an object), inside it you can use
this
variable to refer to this object, for example:If you assign a method from one object to another, its
this
variable refers to the new object, for example:The same thing happens when you assign
requestAnimationFrame
method ofwindow
to another object. Native functions, such as this, has build-in protection from executing it in other context.There is a
Function.prototype.call()
function, which allows you to call a function in another context. You just have to pass it (the object which will be used as context) as a first parameter to this method. For examplealert.call({})
givesTypeError: Illegal invocation
. However,alert.call(window)
works fine, because nowalert
is executed in its original scope.If you use
.call()
with your object like that:it works fine, because
requestAnimationFrame
is executed in scope ofwindow
instead of your object.However, using
.call()
every time you want to call this method, isn't very elegant solution. Instead, you can useFunction.prototype.bind()
. It has similar effect to.call()
, but instead of calling the function, it creates a new function which will always be called in specified context. For example:The only downside of
Function.prototype.bind()
is that it's a part of ECMAScript 5, which is not supported in IE <= 8. Fortunately, there is a polyfill on MDN.As you probably already figured out, you can use
.bind()
to always executerequestAnimationFrame
in context ofwindow
. Your code could look like this:Then you can simply use
support.animationFrame(function() {});
.had this error when I had a VPN connection, disabled the VPN and solved the problem.
In your code you are assigning a native method to a property of custom object. When you call
support.animationFrame(function () {})
, it is executed in the context of current object (ie support). For the native requestAnimationFrame function to work properly, it must be executed in the context ofwindow
.So the correct usage here is
support.animationFrame.call(window, function() {});
.The same happens with alert too:
Another option is to use Function.prototype.bind() which is part of ES5 standard and available in all modern browsers.
You can also use: