
Časovače v JavaScriptu
Jaké nabízí JavaScript možnosti pro vytváření animací. A jak docílit toho, aby byly plynulé.
Pokud chceme na webu něco pohyblivého/animovaného, nabízejí se 3 řešení:
- Použít pohyblivý obrázek GIF / video.
- Použít CSS přechody
transition
nebo vlastnostanimation
s@keyframes
. Tyto CSS animace potom případně spouštět JavaScriptem. - Celou animaci řídit JavaScriptem, který bude měnit CSS vlastnosti (např. umístění, rozměry, průhlednost a podobně) nebo třeba vypisovat nějaký obsah.
Opakované spouštění setInterval
První funkce slouží pro opakované spouštění libovolného JS kódu. Funkce setInterval
má dva parametry, kde první je kód, který se má spustit, a druhý časová prodleva v milisekundách.
Existuje několik způsobů, jak kód pro časovač zapsat.
-
Nejjednodušší je místo prvního parametru napsat řetězec s JS kódem. Následující příklad do elementu s ID „vypsat“ zapíše každých 1000 milisekund (1 vteřina) tečku.
setInterval( "document.getElementById('vypsat').innerHTML += '.'", 1000 );
Psaní kódu do řetězce ale není nic dobrého (jedná se o ekvivalent
eval
u). Proto je lepší se tomuto případu vyhnout. Kromě možných risik při vyhodnocování takového kódu si zbytečně snižujeme čitelnost, protože obsah v řetězci neumí většina editorů správně obarvit. -
Funkci
setInterval
proto raději předáme jako první parametr anonymní/nepojmenovanou funkci:setInterval( function() { // opakovaně spouštěný kód document.getElementById('vypsat').innerHTML += '.'; }, 1000 );
-
Funkci si případně můžeme vytvořit samostatně a
setInterval
u předat jen její název:function vypsat() { // opakovaně spouštěný kód document.getElementById('vypsat').innerHTML += '.'; } var casovac = setInterval(vypsat, 1000);
Pro pozdější zrušení časovače je užitečné si ho přiřadit do proměnné.
Zrušení intervalu clearInterval
Pokud je interval v nějaké proměnné, jde ho na vyžádání zrušit:
clearInterval(casovac);
Na rušení intervalu je dobré nezapomínat, protože to jinak může způsobovat memory leaky.
Spuštění po čase setTimeout
Na rozdíl od setInterval
u spustí požadovanou akci setTimeout
pouze jednou. Jinak jsou si obě funkce dost podobné.
var casovac = setTimeout(
function() {
// kód se spustí pouze jednou za 1000 milisekund
},
1000
);
Zrušení timeoutu clearTimeout
Pokud je timeout v nějaké proměnné, jde ho na vyžádání zrušit:
clearTimeout(casovac);
Zajímavá je skutečnost, že je možné rušit rovněž setInterval
pomocí clearTimeout
a naopak.
Opakované spouštění timeoutu
I pomocí setTimeout
jde nasimulovat setInterval
, tedy zajistit opakované spouštění. V případech, kdy chceme, aby další opakování bylo závislé na tom předchozím, je to i lepší volba.
Celý princip spočívá v rekursivním volání timeoutu. Po provedení vlastní části kódu (vypsání) funkce vypsat
zavolá pomocí setTimeout
samu sebe.
function vypsat() {
// samotný výpis
setTimeout(vypsat, 1000);
}
vypsat();
Jelikož tento kód by běžel nekonečně, možná budeme potřebovat způsob, jak ho zastavit. Existují dvě možnosti.
- Použít
clearTimeout
. Ukázka - Ve funkci
vypsat
na základě splnění nějaké podmínky další časovač nevytvářet. Ukázka
Časování přes requestAnimationFrame
Novější způsob, kterým disponují prohlížeče od IE 10, je použití metody requestAnimationFrame
.
Ta se hodí hlavně pro vytváření animací, protože:
- Automaticky se synchronisuje s obnovovací frekvencí obrazovky (obvykle 60 FPS).
- Pozastavuje se, když je stránka v pozadí nebo není viditelná.
- Poskytuje plynulejší animace než
setInterval
nebosetTimeout
. - Optimalisuje výkon baterie na mobilních zařízeních.
Základní použití:
function animace() {
// kód animace
requestAnimationFrame(animace);
}
requestAnimationFrame(animace);
Příklad jednoduché animace pohybu elementu:
var element = document.getElementById('animovany');
var pozice = 0;
function animace() {
pozice += 2;
element.style.left = pozice + 'px';
if (pozice < 300) {
requestAnimationFrame(animace);
}
}
requestAnimationFrame(animace);
Metodě requestAnimationFrame
je možné jako druhý parametr předat element, kterého se akce v časovači bude týkat. V takovém případě se nemusí akce provádět, když je například element mimo viditelnou plochu.
Zrušení animace cancelAnimationFrame
Pro zrušení animace slouží funkce cancelAnimationFrame
:
var animationId = requestAnimationFrame(animace);
// později...
cancelAnimationFrame(animationId);
Metoda animate
Moderní prohlížeče podporují nativní Web Animations API, které poskytuje metodu element.animate()
. Tato metoda umožňuje vytvářet složité animace přímo v JavaScriptu bez nutnosti psát CSS keyframes.
Základní syntaxe:
element.animate(keyframes, options);
Příklad jednoduché animace:
var element = document.getElementById('animovany');
element.animate([
{ transform: 'translateX(0px)' },
{ transform: 'translateX(200px)' }
], {
duration: 1000,
easing: 'ease-in-out'
});
Pokročilejší animace s více vlastnostmi:
element.animate([
{
opacity: 0,
transform: 'scale(0.5) translateY(-50px)'
},
{
opacity: 1,
transform: 'scale(1) translateY(0px)'
}
], {
duration: 800,
easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
fill: 'forwards'
});
Možnosti v options
objektu:
duration
— délka animace v milisekundách,delay
— zpoždění před začátkem animace,easing
— funkce pro plynulost animace,iterations
— počet opakování (Infinity pro nekonečné),direction
— směr animace (normal, reverse, alternate, alternate-reverse),fill
— chování před a po animaci (none, forwards, backwards, both)
Výhody animate()
metody:
- Nativní podpora v moderních prohlížečích.
- Lepší výkon než manuální změny CSS vlastností.
- Možnost programově ovládat animace (pause, play, reverse).
- Automatická optimalisace prohlížečem.
Ovládání animace:
var animace = element.animate([...], {...});
// pozastavení
animace.pause();
// pokračování
animace.play();
// obrácení
animace.reverse();
// nastavení rychlosti
animace.playbackRate = 2; // dvojnásobná rychlost
Problém s neaktivními taby
Prohlížeče zpomalují nebo pozastavují JavaScript v neaktivních tabech, což ovlivňuje časování a animace.
Různé prohlížeče se chovají jinak, ale obecně jde vycházet z:
- omezení
setTimeout
/setInterval
na cca 1 sekundu, requestAnimationFrame
se pozastaví,- na mobilních zařízeních se pozastaví většina JavaScriptu
Chování se může lišit i podle aktuálního stavu baterie (úsporný režim apod.).
Reagovat na neaktivní taby lze pomocí visibilitychange
.
// Detekce viditelnosti stránky
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// Pozastavit animace
animation.pause();
} else {
// Obnovit animace
animation.play();
}
});
Další možnosti časování
Časování přes Promise
Na pozadí používá setTimeout
pro vytvoření zpoždění/sleep.
// Jednoduché zpoždění
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Použití
async function animovanaSekvence() {
console.log('Začátek');
await delay(1000);
console.log('Po 1 sekundě');
await delay(2000);
console.log('Po dalších 2 sekundách');
}
animovanaSekvence();
Časování ve Web Workers
Pro náročné operace, které by mohly blokovat hlavní vlákno, lze použít Web Workers:
// main.js
const worker = new Worker('timer-worker.js');
worker.postMessage({ type: 'start', interval: 1000 });
worker.onmessage = function(e) {
if (e.data.type === 'tick') {
console.log('Tick z workeru:', e.data.timestamp);
}
};
// timer-worker.js
self.onmessage = function(e) {
if (e.data.type === 'start') {
setInterval(() => {
self.postMessage({
type: 'tick',
timestamp: Date.now()
});
}, e.data.interval);
}
};
Performance API pro přesné měření
Pro velmi přesné měření času lze použít Performance API:
// Měření času s vysokou přesností
const start = performance.now();
setTimeout(() => {
const end = performance.now();
console.log(`Uplynulo: ${end - start} milisekund`);
}, 1000);
Throttling a debouncing
Oba přístupy omezují frekvenci spouštění funkcí, čímž snižují náročnost, ale fungují jinak:
Throttling
Throttling (česky omezování frekvence nebo škrcení) omezuje počet spuštění funkce na maximální hodnotu. Funkce se spustí maximálně jednou za daný časový interval.
// Throttling - omezí frekvenci spouštění
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
}
}
// Použití pro scroll události
window.addEventListener('scroll', throttle(() => {
console.log('Došlo ke scrollování');
}, 100));
Kdy použít throttling:
- Scroll události – reagování na rolování na stránce, které není potřeba tak často.
- Mouse move události – pro sledování pohybu myši.
- Resize události – změna velikosti okna.
- API volání – pro omezení rate limitů.
Debouncing
Debouncing (česky odložení spuštění) počká na konec série událostí a spustí funkci až po určité době klidu. Funkce se spustí pouze jednou po poslední události.
// Debouncing - počká na konec série událostí
function debounce(func, delay) {
let timeoutId;
return function() {
const args = arguments;
const context = this;
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(context, args), delay);
}
}
// Použití pro resize události
window.addEventListener('resize', debounce(() => {
console.log('Došlo ke změně velikosti');
}, 250));
Debouncing se hodí použít, když není potřeba reagovat ihned na každou změnu. Ale stačí to až po nějaké době nečinnosti:
- vyhledávání – pro vyhledávání při psaní nemusí být efektivní hledat po zadání každého znaku,
- validace formulářů – nemusí být potřeba validovat okamžitě,
- automatické ukládání
Hodí se zvlášť pro výpočetně náročné operace nebo API volání. Pro rychlé věci může být uživatelsky přívětivější reagovat hned.
Kdy použít kterou metodu
Výběr správné metody závisí na konkrétním použití:
setInterval
/setTimeout
– pro jednoduché opakované akce, které nejsou visuální animace,requestAnimationFrame
– pro plynulé visuální animace a hry,element.animate()
– pro deklarativní animace s komplexními přechody,- CSS animace – pro jednoduché přechody a animace, které nevyžadují JavaScript logiku,
- Web Workers – pro náročné výpočty bez blokování UI
Odkazy jinam
- CSS Tricks: Using requestAnimationFrame
- Polyfill pro starší prohlížeče — zjednodušená podoba
- MSDN: Timing control for script-based animations ("requestAnimationFrame")
- Paul Irish: requestAnimationFrame for Smart Animating
- Creative JS: requestAnimationFrame
- HTML5Rocks:Web Animations - element.animate() is now in Chrome 36
- GoSquared Blog: Optimising for 60fps everywhere
- MDN: Web Animations API
- Can I Use: Web Animations API browser support
Související články


JavaScript null
a undefined
Rozdíly mezi null
a undefined
v JavaScriptu, kdy je používat a jak se vyhnout běžným chybám.

Sleep v JavaScriptu
Jak implementovat sleep/delay funkcionalitu v JavaScriptu pomocí Promise
a async
/await

JavaScript Battery API
Jak v JS zjistit stav baterie, co dnes funguje a kdy API nepoužívat.