calling a Javascript anonymous function right when it's declared, doesn't work, calling it later does
Solution 1
requestAnimationFrame
expects a function, but in your code, step
is not a function, it is undefined
because you don't return any value from your self-invoking function.
var step = (function(){
// this code is executed immediately,
// the return value is assigned to `step`
})();
If you remove the calling parenthesis, then step
is indeed a function.
Please see @Martin's comment to this answer. I was referring to the fact that step
is undefined
after the function is executed, but of course it is also undefined
when you invoke the function the first time.
Solution 2
I see some fundamental misunderstanding of what's going on here. For example, in your first declaration:
var requestAnimationFrame = ( function() {
return window.requestAnimationFrame || //Chromium
window.webkitRequestAnimationFrame || //Webkit
window.mozRequestAnimationFrame || //Mozilla Geko
window.oRequestAnimationFrame || //Opera Presto
window.msRequestAnimationFrame || //IE Trident?
function(callback) { //Fallback function
window.setTimeout(callback, 1000/60);
}
})();
You're creating an anonymous function, then immediately calling it and assigning the result to a variable. I don't see the point of this. The following would work equally well:
var requestAnimationFrame =
window.requestAnimationFrame || //Chromium
window.webkitRequestAnimationFrame || //Webkit
window.mozRequestAnimationFrame || //Mozilla Geko
window.oRequestAnimationFrame || //Opera Presto
window.msRequestAnimationFrame || //IE Trident?
function(callback) { //Fallback function
window.setTimeout(callback, 1000/60);
};
There's no anonymous function now (well except for the little fallback function), it's just code that runs. You can apply a similar simplification to your step()
function.
Solution 3
Among the issues is this (corrected):
var step = function(){
now = new Date().getTime();
hits += 1;
if( now - last >= 1000 ){
last += 1000;
console.log( "fps: "+ hits );
hits = 0;
}
requestAnimationFrame( step );
};
Solution 4
Your current code essentially says "run this anonymous function and assign its return value to step
". There are two basic problems with this:
- The function doesn't return a value, so even after it runs
step
will be undefined. - Even if the function did return a value, you are trying to use
step
inside the function the first time it runs, at which point the assignment tostep
has not yet taken place.
The simplest way to fix this is what you already did, i.e., declare step
as a function and then run it on the next line:
var step = function() { ... };
step();
Or you could use a named function expression:
(function step() {
...
requestAnimationFrame( step );
})();
Which is the equivalent of:
(function () {
...
requestAnimationFrame( arguments.callee );
})();
Unfortunately IE isn't that great at named function expressions.
And also unfortunately (unfortunate from my point of view, anyway) arguments.callee
is now deprecated and won't work in strict mode.
Solution 5
I see a couple of issues. You are assigning step the return value of the anonymous function. Whereas, when you remove the parentheses. You are making step a function. Since you are not returning a value in the anonymous function, step
is undefined
. Therefore, you will get a type error. I would remove the parentheses at the end.
Petruza
General software engineer, golang advocate, also typescript, C, C++, GDScript dev. Interested in emulation, video games, image processing, machine learning, computer vision, natural language processing, web scraping.
Updated on June 06, 2022Comments
-
Petruza almost 2 years
[answered]
I'm testing my browser's fps for an html5 game.
I have this code:var requestAnimationFrame = ( function() { return window.requestAnimationFrame || //Chromium window.webkitRequestAnimationFrame || //Webkit window.mozRequestAnimationFrame || //Mozilla Geko window.oRequestAnimationFrame || //Opera Presto window.msRequestAnimationFrame || //IE Trident? function(callback) { //Fallback function window.setTimeout(callback, 1000/60); } })(); var hits = 0; var last = new Date().getTime(); var step = (function(){ now = new Date().getTime(); hits += 1; if( now - last >= 1000 ){ last += 1000; console.log( "fps: "+ hits ); hits = 0; } requestAnimationFrame( step ); })();
It gives the following error on Chrome:
Uncaught Error: TYPE_MISMATCH_ERR: DOM Exception 17
On line #27:requestAnimationFrame( step );
W3 says this error is:
If the type of an object is incompatible with the expected type of the parameter associated to the object.
But I'm not actually interacting with the DOM at all, except forwindow
But if I remove the calling parentheses of the anonymous function assigned to
step
and instead just declare that function and on a new line I put:
step();
It works.
Why is this?
Shouldn't both work the same? -
Martin Jespersen over 12 years+1 And even if step wasn't undefined at the point it gets called, it would still be undefined after since the immediate function doesn't return anything.
-
Felix Kling over 12 years@Martin: Right, I was actually referring to this issue and did not even notice that it is also
undefined
when the function is invoked. Thanks! -
Felix Kling over 12 yearsYou are right, it is not necessary to use an anonymous function here. I assume the code is some variant of: paulirish.com/2011/requestanimationframe-for-smart-animating
-
Greg Hewgill over 12 years@FelixKling: Good catch. Copy-paste programming rules!
-
Petruza over 12 yearsYou're right, I was a victim of copy & paste, but what you say makes more sense.
-
Petruza over 12 yearsThanks! it is so obvious now, but I didn't see it. The
DOM
error distracted me. -
Jonathan M over 12 yearsYou had
step
assigned to the result of a function, instead of a function itself. My correction here assigns the function tostep
. -
Petruza over 12 yearsOh right, your comment would have explained it better than the code. Thanks!