Przejdź do treści PWA

XMLHttpRequest, czyli natywny AJAX

Dziś zajmiemy się AJAXem. Za tym określeniem stoi zapytanie do serwera, które jest inicjowane kodem JavaScript. Jeśli chcemy po załadowaniu już całej strony znowu pobrać z serwera dane, to możemy stworzyć takie zapytanie i pobrać tylko dane nam potrzebne.

Baner promujący artykuł

W standardowych stronach internetowych pobieramy nie tylko dane, ale wszystko o stronie, czyli np. wygląd (CSS) oraz strukturę HTML, czyli generujemy odświeżenie. Nie potrzebuje znowu pobierać definicji wyglądu strony - przecież ona już raz się wyrenderowała i dobrze wygląda.

Odświeżenia są kosztowne i nie korzystne dla wszystkich. Dla klienta, bo czeka aż "strona się załaduje". Dla serwera, bo musi znowu zwracać dużo więcej danych (musi odpowiedzieć na większą ilość zapytań do niego).

Spróbujemy stworzyć w czystym JavaScript zapytanie do serwera, pobierające tylko te dane, które faktycznie potrzebujemy.

Konstrukcja zapytania

Tworzymy nowy obiekt XMLHttpRequest, który pomoże nam w stworzeniu zapytania do serwera. W odpowiedzi wcale nie musimy otrzymywać pliku w formacie XML. XML jest to format opisu dokumentu, a nie format wymiany danych. Szczególnie w JavaScript nie używamy XMLa, mamy coś lepszego - format JSON.

Forma notacji JSON jest standardem zdefiniowanym w dokumencie ECMA-404. Na stronie głównej projektu jest pełny opis formatu w sposób (może) bardziej zrozumiały niż zapis standardu ECMA.

JSON jest super pomocny, ze względu na to, że jest bardzo podobny do zwykłego obiektu literałowego.

var xhr = new XMLHttpRequest();
console.log(xhr.readyState); // 0, czyli `XMLHttpRequest.UNSENT`

Inicjacja połączenia

Inicjujemy połączenie. Tutaj dopiero zmieniamy stan naszego zapytania z 0 (UNSET) na 1 (OPENED). Jak się przedstawiają parametry jakie musimy podać do prawidłowo stworzonego zapytania.

  • W pierwszym parametrze ustawiamy metodę protokołu HTTP. Metoda GET służy do pobierania danych z serwera. Jest ona używana w 90% przypadków komunikacji z serwerem.
  • Drugi parametr to string (łańcuch znaków) w którym jest ścieżka (albo URI) do pliku, który chcemy pobrać. Uwaga! Nie wszystkie zasoby w sieci możemy pobierać. Jest zabezpieczenie w przeglądarkach, które nazywane jest Same-origin policy. Zabezpieczenie to blokuje nam (domyślnie) zapytania do innych serwerów. Jeśli jednak serwer na którym jest plik (który chcemy pobrać) wspiera CORS, to problem przestanie istnieć. CORS to technika zarządzania nagłówkami w konkretny sposób.
  • Kolejny parametr to flaga, odpowiadająca na pytanie, czy to zapytanie ma nie blokować zasobu aplikacji uruchomione w przeglądarce? Jeśli ustawimy na false to możemy zablokować naszą aplikację na dobre kilka sekund.
  • Kolejne 2 parametry są potrzebne tylko w sytuacji kiedy mamy włączaną podstawową autoryzację HTTP, czyli tzw. "Basic access authentication"
xhr.open('GET', 'data.json', true);
console.log(xhr.readyState); // 1, czyli `XMLHttpRequest.OPENED`

Kiedy będziemy znali odpowiedź?

Funkcja xhr.onreadystatechange (czyli handler), jest ona uruchomiona z każdym zmianą stanu w zapytaniu do serwera.

Trzy kolejne stany są tutaj użyte:

  • 2, wartość ta jest dostępna we właściwości XMLHttpRequest.HEADERS_RECEIVED
    Stan ten oznacza, że zapytanie pobrało już nagłówki z serwera i tylko nagłówki zapytania HTTP.
  • 3, wartość ta jest dostępna we właściwości XMLHttpRequest.LOADING
    Stan w którym ładujemy nasze dane. Im większy plik, tym ten stan będzie trwał dłużej.
  • 4, wartość ta jest dostępna we właściwości XMLHttpRequest.DONE
    Ostatni stan informuje nas, że zapytanie do serwera się zakończyło.
xhr.onreadystatechange = function () {
    if (this.readyState === XMLHttpRequest.DONE) {
        // Odpowiedź z serwera pobieramy w tym miejscu.
        // Uwaga: tutaj oczekujemy odpowiedzi w formacie JSON.
        console.log(JSON.parse(this.responseText));
    }
};

We właściwości responseText mamy dostępną odpowiedź z serwera. Jeśli tą odpowiedzą jest plik w formacie XML, to odpowiedź dostępna jest we właściwości responseXML. Dzięki funkcji JSON.parse zamieniamy łańcuch znaków na obiekt JavaScript-owy.

Wysyłamy zapytanie

Ostatnia funkcja z tych najważniejszych w AJAX, czyli wysłanie wcześniej stworzonego zapytania.

xhr.send();

Koniec?

Co tutaj się zadziało? Po prostu stworzyliśmy zapytanie do serwera. Sklejmy cały kod w jeden.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'data.json', true);
xhr.onreadystatechange = function () {
    if (this.readyState === XMLHttpRequest.DONE) {
        // Odpowiedź z serwera pobieramy w tym miejscu.
        console.log(JSON.parse(this.responseText));
    }
};
xhr.send();

Dobrą praktyką jest, zamknięcie tego kawałka kodu w funkcję, która będzie przyjmowała 2 parametry: url oraz callback - czyli wywołanie zwrotne.

function makeRequest(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function () {
        if (this.readyState === XMLHttpRequest.DONE) {
            callback(this.responseText);
        }
    };
    xhr.send();
}

Teraz możemy tej funkcji używać w przyjemy sposób bez zbędnego kopiowania kodu, czyli według zasady DRY - DON'T REPEAT YOURSELF:

makeRequest('data.json', function (response) {
    console.log(response);
});