Вызов анонимной функции Javascript правильно, когда она объявлена, не работает, вызов ее позже - PullRequest
1 голос
/ 21 декабря 2011

[ответил]

Я проверяю fps моего браузера для игры html5.
У меня есть этот код:

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

Это даетследующая ошибка в Chrome:
Uncaught Error: TYPE_MISMATCH_ERR: DOM Exception 17
В строке # 27: requestAnimationFrame( step );

W3 говорит, что эта ошибка: If the type of an object is incompatible with the expected type of the parameter associated to the object.
Но я на самом деле не взаимодействую с DOMвообще, за исключением window

Но если я уберу вызывающие скобки анонимной функции, назначенной на step, и вместо этого просто объявлю эту функцию и в новой строке я добавлю:
step();

Это работает.
Почему это так?
Разве оба не должны работать одинаково?

Ответы [ 5 ]

9 голосов
/ 21 декабря 2011

requestAnimationFrame ожидает функцию, но в вашем коде step не является функцией, это undefined, потому что вы не возвращаете никакого значения из своей самопризывающей функции.

var step = (function(){
    // this code is executed immediately, 
    // the return value is assigned to `step` 
})();

Если вы удалите вызывающую скобку, то step действительно является функцией.

Пожалуйста, смотрите @ Martin комментарий к этому ответу.Я имел в виду тот факт, что step - это undefined после , когда функция выполняется, но, конечно, это также undefined, когда вы вызываете функцию в первый раз.

2 голосов
/ 21 декабря 2011

Среди вопросов это (исправлено):

var step = function(){
    now = new Date().getTime();
    hits += 1;
    if( now - last >= 1000 ){
        last += 1000;
        console.log( "fps: "+ hits );
        hits = 0;
    }
    requestAnimationFrame( step );
};
2 голосов
/ 21 декабря 2011

Я вижу фундаментальное недопонимание того, что здесь происходит. Например, в вашей первой декларации:

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

Теперь нет анонимной функции (ну, кроме маленькой резервной функции), это просто код, который выполняется. Вы можете применить аналогичное упрощение к вашей функции step().

1 голос
/ 21 декабря 2011

Ваш текущий код в основном говорит: «Запустите эту анонимную функцию и присвойте ее возвращаемое значение step». Есть две основные проблемы с этим:

  1. Функция не возвращает значение, поэтому даже после запуска step будет неопределенным.
  2. Даже если функция вернула значение, вы пытаетесь использовать step внутри функции при первом запуске, и в этот момент присвоение step еще не произошло.

Самый простой способ исправить это - то, что вы уже сделали, то есть объявить step как функцию и затем запустить ее в следующей строке:

var step = function() { ... };
step();

Или вы можете использовать именованное выражение функции:

(function step() {
   ...
   requestAnimationFrame( step );
})();

Что эквивалентно:

(function () {
    ...
    requestAnimationFrame( arguments.callee );
})();

К сожалению IE не так хорош в выражениях именованных функций .

А также, к сожалению (в любом случае, к сожалению, с моей точки зрения) arguments.callee теперь устарело и не будет работать в строгом режиме.

1 голос
/ 21 декабря 2011

Я вижу пару вопросов. Вы присваиваете шаг возвращаемое значение анонимной функции. Принимая во внимание, когда вы удалите скобки. Вы делаете шаг функцией. Поскольку вы не возвращаете значение в анонимной функции, step равно undefined. Следовательно, вы получите ошибку типа. Я бы убрал скобки в конце.

...