• Frontend i UX/UI
  • Ajax i Fetch - Szybki Frontend, Lepszy UX - Jak to zrobić?

Ajax i Fetch - Szybki Frontend, Lepszy UX - Jak to zrobić?

Jeremi Andrzejewski 9 maja 2026
AJAX: XMLHttpRequest vs Fetch API. Porównanie metod w programowaniu webowym.

Spis treści

Asynchroniczne pobieranie danych pozwala odświeżać fragmenty interfejsu bez przeładowania całej strony, a to bezpośrednio wpływa na szybkość odczuwaną przez użytkownika. W praktyce chodzi o formularze, wyszukiwanie na żywo, filtry produktów, koszyk czy podpowiedzi, które mają reagować natychmiast. W tym tekście pokazuję, jak Ajax działa w nowoczesnym frontendzie, jak go używać rozsądnie i co zrobić, żeby nie popsuć UX ani dostępności.

Najważniejsze rzeczy o Ajaxie, zanim wejdziesz w implementację

  • Ajax to sposób pobierania danych bez pełnego przeładowania strony, a dziś najczęściej realizuje się go przez fetch().
  • Największą korzyść daje tam, gdzie liczy się szybka, częściowa aktualizacja: wyszukiwarka, filtry, walidacja formularzy i dynamiczne listy.
  • Dobrze zaprojektowany interfejs musi pokazać stan ładowania, błąd i ewentualny powrót do poprzedniego stanu.
  • W 2026 roku XMLHttpRequest zostawiam głównie do starszego kodu i przypadków, w których potrzebny jest szczegółowy progres transferu.
  • Przy częstych запросach warto stosować debounce, anulowanie starych żądań i prosty fallback dla klasycznego submitu formularza.

Czym jest Ajax i dlaczego nadal ma sens

Ajax kojarzy się z dawnym terminem Asynchronous JavaScript and XML, ale dziś chodzi już raczej o cały wzorzec komunikacji z serwerem niż o sam XML. W praktyce przeglądarka wysyła żądanie HTTP w tle, a po odebraniu odpowiedzi aktualizuje tylko potrzebny fragment widoku. Dzięki temu strona nie „mruga” pełnym przeładowaniem, a użytkownik nie traci kontekstu.

MDN słusznie podkreśla, że współczesne aplikacje częściej korzystają z fetch() niż z klasycznego XMLHttpRequest. Ja traktuję to jako ważną zmianę podejścia: Ajax nie jest już osobną sztuczką, tylko naturalnym elementem budowania interfejsów, które mają reagować płynnie. Najlepiej widać to w aplikacjach opartych o JSON, gdzie backend w Pythonie zwraca gotowe dane, a frontend renderuje je w miejscu, bez przerywania pracy użytkownika.

Najczęstsze zastosowania są bardzo praktyczne: autouzupełnianie, filtrowanie list, paginacja bez przeładowania, dodanie produktu do koszyka, zapis ustawień, sprawdzanie dostępności nazwy użytkownika czy walidacja formularza po stronie serwera. To właśnie dlatego temat nadal ma znaczenie, nawet jeśli samo słowo „Ajax” pojawia się coraz rzadziej w dokumentacji i rozmowach zespołowych. Żeby wykorzystać ten wzorzec dobrze, trzeba jednak zrozumieć cały cykl żądania, a nie tylko samą funkcję wysyłającą dane.

Jak działa asynchroniczne żądanie od kliknięcia do aktualizacji widoku

Mechanizm jest prosty, ale diabeł siedzi w szczegółach. Użytkownik wykonuje akcję, na przykład wpisuje tekst w wyszukiwarkę albo klika filtr. Frontend zbiera dane wejściowe, wysyła żądanie do endpointu i od razu wraca do normalnej pracy, zamiast blokować interfejs. Odpowiedź przychodzi później, a aplikacja aktualizuje tylko ten fragment DOM, który faktycznie się zmienił.

  1. Użytkownik wyzwala zdarzenie, na przykład input lub click.
  2. Frontend buduje żądanie HTTP i wysyła je asynchronicznie.
  3. Interfejs pokazuje stan oczekiwania, zamiast udawać, że nic się nie dzieje.
  4. Serwer zwraca dane, zwykle w formacie JSON.
  5. Warstwa UI renderuje wynik i ewentualnie przywraca możliwość dalszej interakcji.

Najważniejszy detal to moment, w którym przestajesz myśleć o „pobraniu danych”, a zaczynasz myśleć o stanie interfejsu. Dla użytkownika nie liczy się samo żądanie, tylko to, czy widzi sensowną reakcję systemu. Jeśli odpowiedź przyjdzie po sekundzie, ale UI nie pokaże nic przez cały ten czas, odczucie będzie gorsze niż przy wolniejszym, ale dobrze zakomunikowanym procesie.

W praktyce trzeba też uważać na sytuacje, w których kilka żądań leci jedno po drugim, na przykład podczas szybkiego wpisywania tekstu. Starsza odpowiedź może przyjść po nowszej i nadpisać aktualny stan widoku. To klasyczny problem, który trzeba rozwiązać logiką aplikacji, a nie liczyć na szczęście. Dalej właśnie o tym, jak taki przepływ przełożyć na dobry UX, a nie tylko poprawny kod.

Wizualizacje wdrożeń ajax programowanie: spinner, skeleton loader, progress circle, progress bar, animowane ikony, tekst ładowania, wskaźnik procentowy i hybrydowe wskaźniki.

Jak projektować interfejs wokół asynchronicznych odpowiedzi

W tej warstwie Ajax albo wygrywa, albo przegrywa całe doświadczenie. Gdy projektuję taki interfejs, zaczynam od trzech stanów: ładowanie, sukces i błąd. Bez tego użytkownik widzi tylko pustkę albo nagłą zmianę treści, a to zawsze wygląda jak błąd, nawet jeśli backend działa poprawnie.

Najbardziej praktyczne są trzy reguły, które stosuję bez zastanowienia:

  • Nie pokazuj spinnera od pierwszej milisekundy. Przy odpowiedziach szybszych niż około 300-500 ms lepiej często nic nie migać, bo sam spinner potrafi wprowadzić chaos.
  • Przy dłuższym oczekiwaniu użyj skeletona albo subtelnego komunikatu. Po około 1 sekundzie użytkownik powinien już widzieć, że aplikacja pracuje.
  • Nie zostawiaj starego stanu bez komentarza. Jeśli wyniki się zmieniają, pokaż, że są odświeżane, a nie „zawieszone”.

Do tego dochodzi tzw. optimistic UI, czyli natychmiastowa zmiana widoku jeszcze przed potwierdzeniem z serwera. To działa świetnie przy prostych akcjach, takich jak polubienie, zapis ustawienia czy dodanie elementu do koszyka, ale tylko wtedy, gdy potrafisz cofnąć zmianę w razie błędu. Nie używałbym tego mechanizmu przy operacjach, które mają większą wagę biznesową albo mogą powodować realne konflikty danych.

Warto też zadbać o mikrocopy. Komunikat „Błąd” niewiele mówi, a „Nie udało się pobrać ofert. Spróbuj ponownie za chwilę” naprawdę pomaga. To samo dotyczy stanu pustego: jeśli filtr nie zwrócił wyników, napisz to wprost i pokaż sugestię, co można zmienić. Kiedy interfejs prowadzi użytkownika przez stan oczekiwania i ewentualny problem, wybór technologii przestaje być abstrakcją, więc pora zestawić najważniejsze narzędzia.

Fetch i XMLHttpRequest czego użyć w 2026

Jeśli buduję nowy frontend, najczęściej wybieram fetch(). MDN opisuje go jako nowocześniejszy i bardziej elastyczny zamiennik XMLHttpRequest, a w codziennej pracy to po prostu wygodniejsze narzędzie. Kod jest czytelniejszy, lepiej współgra z async/await i łatwiej go utrzymać w większym projekcie.

Kryterium fetch() XMLHttpRequest
Styl pracy Promise, łatwe async/await Callbacki i zdarzenia
Czytelność Zwykle wyższa, zwłaszcza w większym kodzie Niższa, szczególnie przy kilku warunkach
Integracja z nowoczesnym frontendem Bardzo dobra Poprawna, ale starsza stylistycznie
Obsługa progresu transferu Bywa bardziej ograniczona Często wygodniejsza, szczególnie przy uploadzie
Najlepsze zastosowanie Nowe aplikacje, API JSON, zwykłe odczyty i zapisy Legacy code, wybrane przypadki z progressem

W praktyce różnica jest prosta: fetch() wybieram tam, gdzie chcę szybciej pisać i łatwiej utrzymywać kod, a XMLHttpRequest zostawiam tam, gdzie już istnieje albo gdzie naprawdę potrzebuję jego specyficznych możliwości. Jeśli pracujesz z backendem w Django, Flasku albo FastAPI, fetch() niemal zawsze będzie naturalnym wyborem do pobierania JSON-u i wysyłania danych formularzy. Sam wybór narzędzia to jednak dopiero połowa sukcesu, bo równie ważne jest to, jak zabezpieczysz przepływ danych i reakcję na błędy.

Jak wdrożyć to bez utraty dostępności i kontroli nad błędami

Największy błąd, jaki widzę w projektach frontendowych, to traktowanie asynchronicznych żądań jak czystej techniki, a nie elementu produktu. Użytkownik nie powinien zgadywać, co się dzieje. Powinien wiedzieć, czy aplikacja czeka, przetwarza dane, odrzuciła żądanie, czy po prostu nie dostała odpowiedzi z serwera.

W praktyce trzymam się kilku zasad:

  • Przy wyszukiwaniu i filtrach stosuję debounce 250-400 ms, żeby nie bombardować API każdym znakiem.
  • Anuluję stare żądania przez AbortController, jeśli użytkownik już wpisał nowy tekst albo zmienił filtr.
  • Przy formularzach zostawiam klasyczny fallback, czyli normalny submit, jeśli JavaScript nie zadziała lub użytkownik wyłączy skrypty.
  • Komunikaty błędów piszę po ludzku, bez technicznego żargonu i bez ukrywania przyczyny.
  • Do ważnych zmian stanu używam aria-busy i aria-live, żeby czytniki ekranu mogły odczytać aktualizację.

Przy dłuższych operacjach, zwłaszcza gdy odpowiedź może zająć kilka sekund, warto też przemyśleć retry i timeout. Nie chodzi o agresywne ponawianie wszystkiego, tylko o sensowną reakcję na chwilowe problemy sieciowe. Jeśli po 8-10 sekundach nic się nie dzieje, użytkownik powinien dostać jasny komunikat i opcję ponowienia akcji. Poniżej pokazuję prosty wzorzec, który dobrze sprawdza się przy dynamicznym wyszukiwaniu.

let currentController = null;

async function loadProducts(query) {
  if (currentController) {
    currentController.abort();
  }

  currentController = new AbortController();

  try {
    setLoading(true);

    const response = await fetch(`/api/products?q=${encodeURIComponent(query)}`, {
      signal: currentController.signal,
      headers: {
        Accept: 'application/json'
      }
    });

    if (!response.ok) {
      throw new Error('Nie udało się pobrać danych');
    }

    const items = await response.json();
    renderProducts(items);
  } catch (error) {
    if (error.name !== 'AbortError') {
      showError('Spróbuj ponownie za chwilę');
    }
  } finally {
    setLoading(false);
  }
}

Taki kod nie tylko ogranicza chaos przy szybkim wpisywaniu, ale też zmniejsza liczbę niepotrzebnych odpowiedzi, które później trzeba odfiltrowywać w UI. Gdy ta warstwa jest opanowana, zostają już głównie błędy wykonawcze, które można wyłapać i poprawić dość szybko.

Najczęstsze błędy, które psują efekt mimo poprawnego kodu

Najbardziej kosztowne pomyłki nie są zwykle technicznie spektakularne. To drobne zaniedbania, które po prostu obniżają odczuwalną jakość produktu. Frontend działa, requesty wracają, ale użytkownik ma wrażenie, że interfejs jest nerwowy albo nieprzewidywalny.

  • Brak stanu ładowania powoduje, że użytkownik klika drugi raz, bo nie wie, czy akcja została przyjęta.
  • Odpowiedzi przychodzące w złej kolejności potrafią nadpisać aktualny widok starszym wynikiem.
  • Każdy znak w polu wyszukiwania wywołuje osobne żądanie, co zabija zarówno UX, jak i wydajność API.
  • Brak obsługi błędu sprawia, że aplikacja milczy dokładnie wtedy, gdy użytkownik potrzebuje wskazówki.
  • Pomijanie dostępności kończy się tym, że część osób nie rozumie, że treść właśnie się zmieniła.
  • Zbyt agresywny optimistic UI daje wrażenie szybkości, ale bez planu cofnięcia zmian wprowadza chaos po stronie danych.

Jest jeszcze jeden błąd, który szczególnie często widzę w zespołach skupionych na samej implementacji: próba naprawiania powolnego backendu wyłącznie po stronie przeglądarki. To nie zadziała w dłuższej perspektywie. Jeśli API odpowiada po kilka sekund, frontend może to co najwyżej lepiej zamaskować. Dlatego Ajax traktuję jako narzędzie do poprawy interakcji, a nie jako plaster na wszystko. Właśnie z takiego podejścia płynie najwięcej praktycznej wartości, więc na koniec zostawiam to w najkrótszej możliwej formie.

Co zostawić w kodzie i w głowie po wdrożeniu asynchronicznych zapytań

Najlepszy efekt daje prosty zestaw zasad: pobieraj tylko to, czego naprawdę potrzebujesz, pokazuj użytkownikowi aktualny stan, anuluj nieaktualne żądania i nie ukrywaj błędów za milczeniem interfejsu. To działa zarówno w małych formularzach, jak i w większych aplikacjach z dynamicznymi filtrami czy panelem administracyjnym.

Jeśli mam wybrać jedną rzecz, którą warto zapamiętać po pracy z Ajaxem, to jest nią myślenie o przepływie użytkownika, a nie o samej funkcji pobierającej dane. Technicznie można zrobić wiele rzeczy „tak jak się da”, ale produkt zyskuje dopiero wtedy, gdy każdy request ma sens, każde oczekiwanie jest zakomunikowane, a każdy błąd prowadzi do kolejnego sensownego kroku. Wtedy frontend staje się naprawdę użyteczny, a nie tylko nowoczesny z nazwy.

FAQ - Najczęstsze pytania

Ajax to technika asynchronicznego pobierania danych z serwera bez przeładowywania całej strony. Mimo że termin "Ajax" jest starszy, jego idea – dynamiczna aktualizacja interfejsu – jest kluczowa dla nowoczesnych, płynnych aplikacji webowych, często realizowana dziś przez funkcję `fetch()`.

Asynchroniczne zapytania są idealne tam, gdzie potrzebna jest szybka, częściowa aktualizacja widoku: w wyszukiwarkach z autouzupełnianiem, filtrach produktów, walidacji formularzy na żywo, dynamicznych koszykach czy paginacji bez odświeżania strony.

`fetch()` to nowocześniejsze API oparte na Promise, co ułatwia pracę z `async/await` i czyni kod bardziej czytelnym. `XMLHttpRequest` jest starszy, oparty na callbackach, ale nadal użyteczny w legacy code lub gdy potrzebna jest szczegółowa kontrola nad postępem transferu, np. przy uploadzie plików.

Kluczowe jest pokazanie stanu ładowania, obsługa błędów, anulowanie nieaktualnych żądań (`AbortController`) oraz stosowanie debounce przy częstych zapytaniach. Ważne jest też dbanie o dostępność (np. `aria-live`) i unikanie zbyt agresywnego "optimistic UI" bez mechanizmu cofania zmian.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

ajax programowanie
ajax w nowoczesnym frontendzie
asynchroniczne pobieranie danych javascript
fetch() vs xmlhttprequest
optymalizacja ux z ajax
obsługa błędów ajax
Autor Jeremi Andrzejewski
Jeremi Andrzejewski
Jestem Jeremi Andrzejewski, doświadczonym twórcą treści i analitykiem branżowym, specjalizującym się w technologiach. Od ponad pięciu lat zajmuję się analizowaniem trendów w branży technologicznej oraz pisaniem artykułów, które mają na celu przybliżenie złożonych zagadnień w przystępny sposób. Moje zainteresowania obejmują nowe technologie, innowacje oraz ich wpływ na codzienne życie i biznes. W swojej pracy kładę duży nacisk na rzetelność i aktualność informacji. Staram się dostarczać czytelnikom obiektywne analizy oraz sprawdzone dane, które mogą pomóc im w podejmowaniu świadomych decyzji. Moim celem jest nie tylko informowanie, ale także inspirowanie do odkrywania możliwości, jakie niesie ze sobą rozwój technologii. Wierzę, że wiedza powinna być dostępna dla każdego, dlatego dokładam wszelkich starań, aby moje teksty były zrozumiałe i użyteczne.

Udostępnij artykuł

Napisz komentarz