Що таке requestAnimationFrame?

  1. Javascript
  2. Javascript
  3. setInterval і частота кадрів
  4. Javascript
  5. І що? У чому підступ?
  6. requestAnimationFrame - шлях до порятунку!
  7. Javascript
  8. Ух ти! Кльово! І що все так безхмарно? .. або є проблеми?
  9. Javascript
  10. Але що робити, якщо я хочу встановити частоту кадрів?
  11. Javascript
  12. Javascript

Кожен, хто хоч трохи користується javascript, намагався реалізувати анімацію Кожен, хто хоч трохи користується javascript, намагався реалізувати анімацію. Це можуть бути меню-акордеони, що випадають меню, щось рухомі, зроблене на canvas або svg або в крайньому випадку сніг, який літає на добрій половині сайтів перед новим роком (не подобається мені він: P). Кращим рішенням у разі анімації, безперечно буде css transitions і animations. Але, на жаль на момент написання статті, ie9 (остання версія ослика) нічого про css анімації не знає, та й в деяких випадках (анімація на canvas наприклад), css ніяк не допоможе.

Давайте розглянемо типову функцію, яку ми використовуємо, коли реалізуємо анімацію:

Javascript

var step = function () {// описуємо один крок} setInterval (step, 100); // повторюємо крок через нажд 0.1с

або так:

Javascript

var step = function () {setTimeout (step, 100); // циклічно виконуємо кроки один за одним, викликаючи функцію саму з себе // описуємо один крок тут} step (); // виконуємо крок в перший раз

setInterval і частота кадрів

Плавність анімації залежить від частоти кадрів. Частота кадрів вимірюється в "кадрах в секунду" (FPS - frame per second). Фільми та відео зазвичай роблять з 24fps - 30fps. Чим більше це число, тим більш гладкою здається анімація. З іншого боку - чим більше fps, тим більше потрібно ресурсів процесора, що може привести до підвисання і пропуску кадрів. Оскільки більшість екранів має частоту оновлення 60 Гц - fps до якого треба прагнути дорівнює 60-ти.

Трохи математики і ідеальний інтервал 1000ms / 60 (fps) = 16.7ms

тобто

Javascript

setInterval (step, 17);

І що? У чому підступ?

Що не так з цією функцією?

По-перше, SetTimeout не бере до уваги те, що ще відбувається в браузері. Сторінка може, наприклад, знаходиться в неактивній вкладці браузера. При цьому вона буде використовувати ресурси процесора незважаючи на це.

До речі розумний Chrome робить setInterval і setTimeout рівним 1fps в прихованих вкладках .. але, наскільки я знаю, так поки робить лише chrome :(

По-друге, SetTimeout вимагає перемальовування сторінки не в той же час, коли це робить ваш комп'ютер (а він робить це регулярно). Це означає, що ваш бідний браузер повинен синхронізувати вашу горе-анімацію з оновленням всього екрану, і якщо її частота не синхронізована з оновленням всього екрану, це може зажадати більше обчислювальної потужності. А це завантаження процесора, нагрів, шум кулера, витрата батареї мобільних девайсів .. і т.п

Ще одним аспектом є анімації декількох елементів відразу. Звичайно, можна спробувати все це синхронізувати, але .. це черговий кошмар, в разі різнопланової анімації, яка відбувається одновремменно.

requestAnimationFrame - шлях до порятунку!

Щоб подолати ці проблеми, Mozilla (творці Firefox) запропонував функцію requestAnimationFrame, яка згодом була прийнята і вдосконалена командою WebKit (Chrome і Safari). Вона забезпечує вбудований API для запуску будь-яких типів анімації в браузері (DOM елементів, canvas, WebGL і ін.)

Javascript

function step () {requestAnimationFrame (step); // описуємо один шаганімаціі тут} step ();

Шикарно! Це ж, як setTimeout, наведений вище, але з requestAnimationFrame замість нього !!! При бажанні ви можете передати ще один параметр - аніміруемий елемент: requestAnimationFrame (step, element);

Однак, як ви могли помітити, ми не вказали інтервал. Як часто бдет викликатися наша функція? Все залежить від частоти кадрів вашого браузера і комп'ютера (зазвичай це 60 кадрів в секунду). Ключовою відмінністю є те, що ви просите браузер виконати функцію (в нашому прикладі step) при першій можливості, а не через встановлені проміжки часу. Ще одна перевага такого підходу в тому, що браузери можуть знизити requestAnimationFrame в залежності від навантаження, видимості елемента і стану батареї.

Ще кілька неоціненних переваг requestAnimationFrame, в тому, що він буде групувати всі ваші анімації в одному браузерному repaint. Це заощадить ресурси процесора і дозволяє вашому пристрою бути швидше і жити довше.

Якщо ви використовуєте requestAnimationFrame, всі ваші анімації будуть гладкими і красивими, синхронізованими з вашим графічним процесором (GPU) і з'їдають набагато менше ресурсів центрального процесора (CPU).

Ух ти! Кльово! І що все так безхмарно? .. або є проблеми?

Ну, да, проблеми поки є, але зовсім дріб'язкові. Це зовсім новий API і .. для Chrome і Safari - це webkitRequestAnimationFrame. Відповідно в Firefox це mozRequestAnimationFrame. Microsoft (Internet Explorer 10) буде підтримувати msRequestAnimationFrame.

Щоб впорається з цим, Eric Möller (Opera), Paul Irish (Google) і Tino Zijdel (Tweakers.net) створили polyfill наведений нижче:

Javascript

(Function () {var lastTime = 0; var vendors = [ 'ms', 'moz', 'webkit', 'o']; for (var x = 0; x <vendors.length &&! Window.requestAnimationFrame; + + x) {window.requestAnimationFrame = window [vendors [x] + 'RequestAnimationFrame']; window.cancelAnimationFrame = window [vendors [x] + 'CancelAnimationFrame'] || window [vendors [x] + 'CancelRequestAnimationFrame'];} if (! window.requestAnimationFrame) window.requestAnimationFrame = function (callback, element) {var currTime = new Date (). getTime (); var timeToCall = Math.max (0, 16 - (currTime - lastTime)); var id = window.setTimeout (function () {callback (currTime + timeToCall);}, timeToCall); lastTime = currTime + timeToCall; return id;}; if (! window.cancelAnimationFrame) window.cancelAnimationFrame = function (id) {clearTimeout ( id);};} ());

Вставляємо в початок коду і requestAnimationFrame працює як рідний. У браузерах, де він взагалі не підтримується, буде ізпользоваться setInterval

Але що робити, якщо я хочу встановити частоту кадрів?

Проблеми полягає в тому, як контролювати fps для requestAnimationFrame, якщо ви не можете вказати частоту кадрів? Це критично для багатьох веб додатків і особливо для ігор.

Ось техніка, яку ви можете використовувати:

Javascript

var fps = 15; function step () {setTimeout (function () {requestAnimationFrame (step); // Drawing code goes here}, 1000 / fps); }

Ваша анімація тепер контролюється браузером і ви можете вказати частоту кадрів до 60 кадрів в секунду.

Більш складна техніка полягає в перевірці кількості мілісекунд, що пройшли з моменту останнього дзвінка анімуйте функції і оновлювати позицію елемента, покладаючись на різницю в часі. наприклад:

Javascript

var time; function step () {requestAnimationFrame (step); var now = new Date (). getTime (), dt = now - (time || now); time = now; // для прикладу зрушення по осі х this.x + = 10 * dt; // Збільшувати х на десять одиниць в секунду}

Хай щастить. Приємного "анімації" :): P

У чому підступ?
І що все так безхмарно?
Або є проблеми?
У чому підступ?
Що не так з цією функцією?
Як часто бдет викликатися наша функція?
І що все так безхмарно?
Або є проблеми?
Проблеми полягає в тому, як контролювати fps для requestAnimationFrame, якщо ви не можете вказати частоту кадрів?