Как использовать requestAnimationFrame?

#javascript #animation #requestanimationframe

#javascript #Анимация #requestanimationframe

Вопрос:

Я новичок в анимации, но недавно создал анимацию с помощью setTimeout . Частота кадров в секунду была слишком низкой, поэтому я нашел решение для использования requestAnimationFrame , описанное по этой ссылке.

Пока что мой код:

 //shim layer with setTimeout fallback
    window.requestAnimFrame = (function(){
        return  
            window.requestAnimationFrame       || 
            window.webkitRequestAnimationFrame || 
            window.mozRequestAnimationFrame    || 
            window.oRequestAnimationFrame      || 
            window.msRequestAnimationFrame     || 
            function(/* function */ callback){
                window.setTimeout(callback, 1000 / 60);
            };
    })();
    (function animloop(){
        //Get metrics
        var leftCurveEndX = finalLeft - initialLeft;
        var leftCurveEndY = finalTop   finalHeight - initialTop;
        var rightCurveEndX = finalLeft   finalWidth - initialLeft - initialWidth;
        var rightCurveEndY = leftCurveEndY;

        chopElement(0, 0, 0, 0, leftCurveEndX, leftCurveEndY, rightCurveEndX, rightCurveEndY);//Creates a new frame 
        requestAnimFrame(animloop);
    })();
  

Это останавливается во время первого кадра. У меня есть функция обратного вызова requestAnimFrame(animloop); в chopElement функции.

Кроме того, существует ли более подробное руководство по использованию этого API?

Комментарии:

1. Как правило, будьте очень осторожны с возвратами в JS, если вы удалите новую строку после возврата, это сработает.

Ответ №1:

Внимание! Этот вопрос не о лучшем способе прокладки requestAnimFrame . Если вы ищете это, перейдите к любому другому ответу на этой странице.


Вас обманула автоматическая вставка точки с запятой. Попробуйте это:

 window.requestAnimFrame = function(){
    return (
        window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     || 
        function(/* function */ callback){
            window.setTimeout(callback, 1000 / 60);
        }
    );
}();
  

javascript автоматически ставит точку с запятой после вашего return утверждения. Это происходит потому, что за ним следует новая строка, а следующая строка является допустимым выражением. Фактически это переводится в:

 return;
window.requestAnimationFrame       || 
window.webkitRequestAnimationFrame || 
window.mozRequestAnimationFrame    || 
window.oRequestAnimationFrame      || 
window.msRequestAnimationFrame     || 
function(/* function */ callback){
    window.setTimeout(callback, 1000 / 60);
};
  

Этот код возвращает undefined и никогда не выполняет код, стоящий за оператором return. Так window.requestAnimFrame и есть undefined . Когда вы вызываете его в animloop , javascript выдает ошибку и останавливает выполнение. Вы можете решить проблему, заключив выражение в круглые скобки.

Могу ли я порекомендовать Chrome developer tools или firebug для проверки выполнения javascript. С помощью этих инструментов вы бы увидели ошибку. Вы должны выполнить его отладку следующим образом (я предполагаю, что Chrome):

  1. Выполните код (он выдает неожиданные результаты)
  2. Откройте инструменты разработчика (щелкните правой кнопкой мыши -> Проверить элемент) Вы увидите красный крестик в строке состояния справа (это означает, что произошла ошибка при выполнении)
  3. Откройте вкладку консоль
  4. Вы увидите

    Неперехваченная ошибка типа: свойство ‘requestAnimFrame’ объекта [object DOMWindow] не является функцией

  5. Введите в консоли: window.requestAnimFrame и нажмите enter, вы увидите, что это undefined . К настоящему моменту вы знаете, что проблема на самом деле не связана с requestAnimationFrame и что вам следует сосредоточиться на первой части вашего кода.
  6. Теперь речь идет о сужении кода до точки, где он возвращает что-то. Это сложная часть, и если вы все еще не нашли ее на данном этапе, возможно, вам захочется обратиться к Интернету за дополнительной помощью.

Кроме того, посмотрите это видео, чтобы узнать о некоторых полезных приемах написания javascript, в нем также упоминается злая автоматическая вставка точки с запятой.

Комментарии:

1. использование этого метода с такими событиями, как scroll или resize в браузерах, которые не поддерживают requestAnimationFrame , будет вызывать обратный вызов постоянно, а не так, как предполагалось, потому что setTimeout будет запускаться постоянно, создавая новые таймеры и запуская их один за другим. метод throttle лучше подходит для компенсации. кроме того, вам не нужно писать window перед каждым global…it это избыточно.

2. написание «window» перед глобальными может дать понять другим разработчикам, читающим код, что они могут быть встроенными и каким-то образом не являются функциями, предоставляемыми в локальной области видимости. Учитывая, насколько сложной может быть область видимости в современных приложениях js с bower / webpack / etc. В наши дни, это разумно. Ничего не повреждает.

Ответ №2:

  /*
  Provides requestAnimationFrame in a cross browser way.
  http://paulirish.com/2011/requestanimationframe-for-smart-animating/
 */

if (!window.requestAnimationFrame) {

    window.requestAnimationFrame = (function() {

        return window.webkitRequestAnimationFrame ||
            window.mozRequestAnimationFrame || // comment out if FF4 is slow (it caps framerate at ~30fps: https://bugzilla.mozilla.org/show_bug.cgi?id=630127)
        window.oRequestAnimationFrame ||
            window.msRequestAnimationFrame ||
            function( /* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {

                window.setTimeout(callback, 1000 / 60);

        };

    })();

}

animate();

function animate() {
    requestAnimationFrame(animate);
    draw();
}

function draw() {
    // Put your code here
}
  

Взгляните на приведенный ниже пример jsfiddle; Он ясно иллюстрирует, что я имею в виду;

http://jsfiddle.net/XQpzU/4358/light/

Надеюсь, это поможет!

Комментарии:

1. Ваш вызов внутри animate() использует неправильное имя функции. Пол действительно использует requestAnimationFrame в своем примере, но вы изменяете requestAnimationFrame (который, кстати, мне нравится больше). Легко исправить.

2. Спасибо за комментарий, Micros! Я отредактировал его. В основном я предпочитаю использовать функции с длинными именами, как вам нравится. Я думаю, что эта привычка пришла ко мне от использования языка obj-c 🙂

Ответ №3:

«Разумное регулирование, чтобы событие не запускалось больше раз, чем экран может перерисовать изменение:

 var requestFrame = window.requestAnimationFrame ||
                   window.webkitRequestAnimationFrame ||
                   // polyfill - throttle fall-back for unsupported browsers
                   (function() {
                       var throttle = false,
                           FPS = 1000 / 60; // 60fps (in ms)
       
                       return function(CB) {
                         if( throttle ) return;
                         throttle = true;
                         setTimeout(function(){ throttle = false }, FPS);
                         CB(); // do your thing
                       }
                    })();

/////////////////////////////
// use case:

function doSomething() {
  console.log('fired');
}

window.onscroll = function() {
  requestFrame(doSomething);
};  
 html, body{ height:300%; }
body::before{ content:'scroll here'; position:fixed; font:2em Arial; }  

Комментарии:

1. Я не знаю, но частота кадров в секунду, возможно, должна быть 1000/60 как 60 кадров в секунду

2. Милая, привет, vsync, ты знаешь что-нибудь об облегчении прокрутки страницы с помощью requestAnimationFrame?

3. @Ampersanda — каким образом облегчить? когда пользователь использует колесо мыши для ручной прокрутки?

4. нормально ли работать requestAnimationFrame без остановки (т. Е. со скоростью 60 кадров в секунду бесконечно)? не слишком ли дорого запускать его все время, даже если его скорость всего 60 кадров в секунду?

5. @oldboy — это супер-нормально и абсолютно не дорого.