Timeout i interwały

Gdy odpalimy nasz skrypt, wykonuje się on natychmiast - linia po linii.

W JavaScript istnieją też asynchroniczne funkcje, które pozwalają odpalić nasz kod z opóźnieniem czasowym, lub pozwalają odpalać taki kod cyklicznie co jakiś czas.

Są to kolejno:

setTimeout(fn, time*, par1*, par2*...)

odpala przekazaną funkcję po jakimś czasie

setInterval(fn, time*, par1*, par2*...)

pozwala odpalić zadaną funkcję cyklicznie co jakiś czas

requestAnimationFrame(fn)

odpala funkcję przed kolejnym rysowaniem naszej strony. Stosowana głównie przy animacjach, dzięki czemu mamy pewność, że dany kod będzie odpalany możliwie płynnie

setTimeout

Pierwszą z takich funkcji jest setTimeout(fn, time*, arg1*, arg2*...) - przydatna w przypadkach gdy np. chcemy po jakimś czasie pokazać jakiś modal, ukryć coś itp. W pierwszym parametrze przekazujemy funkcję, która zostanie odpalana po zadanym czasie. W drugim parametrze podajemy czas w milisekundach - domyślnie wynosi on 0. Czas ten oznacza czas, po jakim zostanie odpalona nasza funkcja.

function myFunc() {
    console.log("Jakiś tekst");
}

setTimeout(myFunc, 1200); //odpali po 1.2s
setTimeout(() => {
    console.log("z zaskoczenia!");
}, 3000);

Przekazywany w drugim parametrze czas jest czasem przybliżonym. To, że podamy tutaj np. 10, nie oznacza, że nasza funkcja zostanie odpalona idealnie za dziesięć milisekund. Czemu tak się dzieje - dowiesz się poniżej.

Żeby przerwać wcześniej zainicjowany setTimeout (ale przed jego wykonaniem) korzystamy z metody clearTimeout() która w parametrze przyjmuje zmienną, pod którą zostało wcześniej podstawione wywołanie setTimeout:

Jeżeli przekazana do setTimeout funkcja wymaga przekazania atrybutów, możemy je podać jako kolejne wartości dla setTimeout:

setInterval

Funkcja setInterval(fn, time*, arg1*, arg2*...) działa podobnie do setTimeout, jednak w przeciwieństwie do powyższej przekazana funkcja będzie odpalana cyklicznie, aż do zatrzymania lub opuszczenia strony przez użytkownika:

Żeby zatrzymać odpalony interwał, skorzystamy z metody clearInterval(), która podobnie do clearTimeout przyjmuje tylko jeden parametr, który jest zmienną, pod która wcześniej zostało podstawione zadeklarowanie setInterval:

Przerwanie interwału możemy też wykonywać z jego wnętrza:

Oczywiście nic nie stoi na przeszkodzie, by łączyć omawiane funkcje:

requestAnimationFrame

Funkcja requestAnimationFrame(fn) pozwala odpalić przekazaną do niej funkcję przed kolejnym rysowaniem (patrz poniżej). Funkcja ta stosowana jest głównie w przypadku wszelakich animacji.

Więcej na temat jej użycia dowiesz się w kolejnym rozdziale. My głównie będziemy jej używać w rozdziale o animacjach w canvas.

Debounce i throttle

Wyobraź sobie, że robisz dynamiczną wyszukiwarkę na stronie. Użytkownik wpisuje litery do pola, a ty co litera wykonujesz za pomocą Ajax do serwera zapytanie, a następnie zwracasz użytkownikowi wyniki.

Problem z takim podejściem jest taki, że większość użytkowników internetu szybko pisze, więc nasze kolejne zapytania będą się bardzo często wykonywać. Zbyt często. Dość szybko spowoduje to przyblokowanie kolejnych zapytań.

Żeby ci to zademonstrować, zróbmy sytuację za pomocą setTimeout, które zastąpi nam dynamiczne połączenie:

Wpisuj szybko jakiś tekst i sprawdź w konsoli:

Ale nie tylko dynamicznych wyszukiwarek się to tyczy. Każda sytuacja, która potencjalnie może odpalać nasz kod zbyt szybko będzie potencjalnie problematyczna.

Tutaj podobny problem - tym razem tyczy się zmiany rozmiaru okna strony (event resize).

Właśnie w takich i podobnych sytuacjach stosuje się omawiane techniki.

Pierwsza z nich nosi nazwę throttle.

Wpisuj szybko jakiś tekst:

Druga z nich nosi nazwę debounce. Najczęściej używaną implementacją debounce jest chyba ta zastosowana w bibliotece lodash, ale możliwych implementacji jest bardzo dużo (np. dla jQuery). Poniżej zamieszczam inną przykładową implementację:

Pokazany wcześniej przykład z problematyczną zmianą rozmiaru okna wraz z zaimplementowaną funkcją debounce

Last updated