Ten epizod skupia się na poznaniu funkcji setTimeout i setInterval, które pozwalają nam na uruchamianie kodu z pewnym opóźnieniem czasowym. Poznamy też pewne dość „życiowe” zastosowanie rekurencji w naszym kodzie.

Kontynuujemy naukę języka JavaScript. Tym razem poznamy sobie nieco zagadnienie funkcji takich jak setTimeout, setInterval a także coś zwanego rekurencją, co już wcześniej mieliśmy okazję poznać.

Jak zwykle podaję templatkę dla pliku HTML, w którym będziemy pisać nasz kod JS w tagach <script> przy pomocy edytora tekstowego (najlepiej VSCode) oraz sprawdzać jak to działa przy użyciu przeglądarki internetowej (najlepiej Chrome):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>Welcome to my website</h1>
    
    <script>
        //nasz kod tutaj
    </script>
</body>
</html>

Do dzieła.

setTimeout – funkcja z opóźnieniem

Rzućmy sobie okiem na taką oto funkcję:

<script>
        function cookieAlert(){
            alert("Our website uses cookies");
        }
        cookieAlert();
    </script>

To tylko symulacja pewnego zachowania, które ma, po wywołaniu funkcji, wyświetlić informację o używaniu plików cookie przez stronę.

No dobrze, a teraz postarajmy się tę funkcję jakoś opóźnić, np. o 3 sekundy. Jak nietrudno się domyślić – służy do tego funkcja setTimeout:

<script>
        function cookieAlert(){
            alert("Our website uses cookies");
        }
        setTimeout(cookieAlert, 3000);
    </script>

setTimeout to naprawdę prosta funkcja. Niewiele więcej tutaj można pokazać, więc tylko zrobimy sobie pewne ostrzeżenie.

Pamiętamy, że poza słówkiem kluczowym 'let’ mamy także słówko kluczowe 'var’. Możemy nim tworzyć zmienne. Także w pętli for:

<script>
        for(let i = 1; i<=10; i++){
            console.log(i);
        }
        for(var i = 1; i<=10; i++){
            console.log(i);
        }
    </script>

Mamy tutaj wypisanie w pętlach for liczb od 1 do 10. Tak var jak i let działają identycznie. A teraz postarajmy się zrobić to samo, ale z var, opóźniając każdą liczbę o 1 sekundę:

<script>
        for(var i = 1; i<=3; i++){
            setTimeout(() => {
            alert(i);
            }, 1000);
        }
    </script>

Wydawać by się mogło, że nasza pętla wyświetli liczby 1,2 i 3, czekając 1 sekundę. Niestety – otrzymujemy liczby 4.

Dlaczego? Bo tak napisana pętla najpierw przechodzi po i, zwiększając je do wartości 4 (pierwsza wartość, która nie spełnia warunku), potem zaś ten setTimeout jest wykonywany.

Nie wchodząc w szczegóły, które ani ciekawe nie są ani potrzebne (na naszym poziomie) – aby tego uniknąć, używamy 'let’:

<script>
        for(let i = 1; i<=3; i++){
            setTimeout(() => {
            alert(i);
            }, 1000);
        }
    </script>

W ogóle – starajmy się używać 'let’, nigdy 'var’, które jest przestarzałe.

setInterval – wykonuj co jakiś czas

setInterval to funkcja, która wykonuje inną funkcję w nieskończoność, z odstępem jaki jej podamy.

<script>
        let cnt = 0
        function count() {
        console.log(cnt++);
        }
        setInterval(count, 1000);
    </script>

Tutaj ustawiliśmy, że funkcja count ma się wykonywać w nieskończoność, co sekundę, i to się dzieje.

Oczywiście, mamy też funkcję clearInterval, która wyłącza interwał, ale ona potrzebuje jego ID.

ID zwraca setInterval. Pomyślmy jak tu się z tym kodem pobawić, aby móc wstrzymać to odliczanie, gdy już będziemy mieli 10?

<script>
        let cnt = 0
        let interval;
        function count() {
        console.log(++cnt);
            if(cnt === 10)
                clearInterval(interval);
        }
        interval = setInterval(count, 1000);
    </script>

Tutaj mamy odliczanie od 1 do 10. Tworzymy zmienną interval, nic nie przypisujemy. Tworzymy naszą logikę funkcji, która gdy cnt osiągnie 10 czyści interwał.

Do zmiennej interval przypisujemy ID, które setInterval zwraca. Tym sposobem jesteśmy w stanie zastopować wykonywanie interwału.

setTimeout – rekurencja, zmienny interwał

Zamiast używać setInterval, możemy też użyć setTimeout rekurencyjnie, czyli w funkcji, która wywołuje samą siebie. Dzięki temu możemy osiągnąć to, co setInterval a nawet więcej – interwał może się zmieniać z każdym nowym wywołaniem.

Oto funkcja, która nie korzysta z setInterval, zaś działa, jakby korzystała:

function repeatingFunc() {
    console.log("It's been 5 seconds. Execute the function again.");
    setTimeout(repeatingFunc, 5000);
}

setTimeout(repeatingFunc, 5000);

Funkcja ta robi console.log i rzuca setTimeout na samą siebie. Dzięki temu będzie wywoływać się w nieskończoność, co 5 sekund.

setTimeout poza funkcją jest po to, aby początkowo ją o te 5 sekund opóźnić. Bo możemy napisać tak:

function repeatingFunc() {
    console.log("It's been 5 seconds. Execute the function again.");
    setTimeout(repeatingFunc, 5000);
}

repeatingFunc();

Teraz funkcja wywoła się za pierwszym razem natychmiast, za każdym kolejnym – 5 sekund opóźnienia.

Podejście rekurencyjne, czyli wywoływanie funkcji przez samą siebie, razem z setTimeout daje nam większą swobodę niż funkcja setInterval.

I to by było w zasadzie na tyle. setTimeout i setInterval nie są szczególnie łatwe ani przesadnie trudne, ale poznaliśmy ich działanie w tym i różne nieoczekiwane bądź mniej oczywiste mechanizmy.

Do następnego razu.