Uvod u AJAX (Asynchronous JavaScript And XML)
Uvod
Termin AJAX (skraćeno od "Asynchronous JavaScript And XML"), predstavlja skup tehnika koje omogućavaju asinhronu komunikaciju između klijenta i servera, ili, jednostavnije (za sam početak), u pitanju je mehanizam koji omogućava automatsko ažuriranje sadržaja delova stranice bez potrebe za ponovnim učitavanjem.
Sa pristupom koji smo opisali, susrećemo se svakodnevno: chat aplikacije, dodavanje komentara koje ne prekida prikazivanje video klipova, sugestije na pretraživačima koje se automatski ažuriraju shodno promenama u polju za pretragu .... samo su neki od primera.
Pored AJAX-a (koji je nešto starija tehnologija), poslednjih godina raste popularnost i novije, modernije tehnologije, Fetch API (kojoj ćemo takođe uskoro posvetiti članak), ali, za početak, zarad upoznavanja sa osnovnim principima asinhrone komunikacije sa serverom, koristićemo 'tradicionalni' AJAX.
Da bismo najbolje razumeli kako AJAX funkcioniše u praksi, kreiraćemo jednostavnu chat aplikaciju (uz poseban osvrt na back-end), i 'usput' ćemo se upoznati sa teorijom.
Nedostaci sinhronog modela
Sinhroni model komunikacije između klijenta i servera, sam po sebi je krajnje adekvatan, ali - u kontekstu web aplikacija koje zahtevaju da se sadržaj stranica osvežava periodično na neupadljiv način (recimo, chat aplikacije), ili, shodno korisničkom unosu i interakciji sa stranicom (komentari ispod video klipova, automatske sugestije pri pretrazi i sl) - sinhroni model ispoljava nedostatke (to jest, "nije baš od pomoći").
Za početak, razmotrićemo šta su osnovni zahtevi koji se postavljaju pred tipičnu chat aplikaciju:
- chat aplikacije (tipično) koriste sledeće HTML elemente:
- polje za prikaz već razmenjenih poruka (za šta sasvim dobro može poslužiti običan
<div>
element) - polje za unos nove poruke (
<input>
) - dugme za slanje nove poruke
- polje za prikaz već razmenjenih poruka (za šta sasvim dobro može poslužiti običan
- back-end chat aplikacije (tipično) čini baza podataka, sa tabelama preko kojih se beleže podaci o korisnicima i poslatim porukama
- kada korisnik unese tekst poruke u odgovarajuće polje i klikne na dugme za slanje, poruka se prosleđuje u bazu podataka
- poruka koja je prethodno poslata u bazu (i upisana u odgovarajuću tabelu), čita se iz baze i pojavljuje na ekranu svih korisnika koji učestvuju u chat-u (zajedno sa prethodno poslatim porukama)
Kada sagledamo listu koju smo prethodno naveli (na početku odeljka), reklo bi se da smo spomenuli sve što je neophodno, ali, "slučajno" smo prevideli jednu 'sitnicu': sve što smo naveli - neće se izvršavati automatski.
Model sinhrone komunikacije između klijenta i servera
Kao što smo već prikazali u ranijim člancima, sinhroni model komunikacije između klijenta i servera, podrazumeva sledeće korake:
- klijent šalje zahtev serveru u obliku URL-a (tj. 'web adrese')
- server prima i obrađuje zahtev i potom šalje klijentu zahtevani HTML sadržaj
- na strani klijenta, primljeni HTML sadržaj se obrađuje i prikazuje u browseru
- ukoliko je potrebno osvežiti sadržaj stranice, šalje se novi zahtev *
Naravno, sve pod uslovom da je zahtev uredno poslat, primljen i obrađen (u slučaju grešaka u obradi zahteva: umesto HTML-a i drugih traženih sadržaja, server će poslati klijentu odgovarajući statusni kod), a napomenimo i to da server, pored HTML-a, na zahtev klijenta šalje i sav drugi pripadajući sadržaj: CSS, JavaScript, kao i druge datoteke (najčešće slike).
Nedostaci sinhronog modela u slučaju chat aplikacije
Ukoliko bismo se oslonili (samo) na sinhroni model (pri izradi chat aplikacije), suočili bismo se sa sledećom situacijom:
- za učitavanje (novih) primljenih poruka, bilo bi potrebno ponovo učitati (tj. osvežiti) celu stranicu
- za slanje poruka, bilo bi potrebno koristiti HTML formular koji (posle klika na dugme za slanje poruke), pokreće skriptu za slanje poruke, pri čemu browser prebacuje korisnika, sa prozora chat aplikacije, na drugu stranicu
Navedene okolnosti svakako predstavljaju problem ukoliko je potrebno da chat aplikacija funkcioniše onako kako su korisnici navikli (godinama unazad) - bez "seckanja", resetovanja i ručnog učitavanja poruka.
Srećom, web browseri (preko JavaScript-a), omogućavaju korišćenje posebnih XMLHttpRequest
objekata, čija je svrha - razmena podataka bez potrebe za ponovnim učitavanjem stranice, a sam AJAX (kao tehnologija koju ćemo u ovom članku koristiti za automatsko ažuriranje chat aplikacije), ni iz daleka nije (previše) komplikovan, i samo preostaje da se upoznamo sa tehnikalijama, i da sve povežemo u funkcionalnu celinu.
AJAX - osnovne postavke
Kao što smo na početku već nagovestili, "AJAX" * je akronim iza koga stoji nekoliko međusobno povezanih tehnika koje za cilj imaju asinhrono ažuriranje delova web stranica (čemu prethodi razmena podataka između klijenta i servera):
- preko objekta
XMLHttpRequest
šalju se 'AJAX zahtevi' (koji tipično podrazumevaju slanje upita i prijem podataka od servera) - podaci se najčešće razmenjuju u vidu JSON objekata **
- JavaScript je jezik preko koga se sve objedinjuje
Pogledajmo kako AJAX zahtevi funkcionišu u praksi ....
AJAX zahtevi - slanje i obrada
Specijalizovani XMLHttpRequest
objekti razmenjuju podatke sa serverom na sledeći način:
- preko događaja
onreadystatechange
pokreće se funkcija povratnog poziva preko koje se (praktično) obavlja komunikacija između klijenta i servera (funkcija se izvršava svaki put kada se stanje zahteva promeni) - preko polja
responseText
, JS skripta dobija odgovor od servera (u obliku običnog teksta, u obliku HTML koda, ili u obliku JSON objekta)
Prvo ćemo sagledati, u celosti, primer funkcije koja koristi XMLHttpRequest
objekat za slanje AJAX poziva i obradu odgovora servera ....
.... posle čega ćemo detaljno analizirati delove.
Provera stanja zahteva
Neimenovana funkcija povratnog poziva, koja se povezuje sa događajem onreadystatechange
....
.... ispituje stanje (poslatog) zahteva, i statusni kod koji je primljen od servera (ukoliko je zahtev rešen).
Kada funkcija očita stanje 4
i status 200
, izvršavaju se sledeće komande (koje smo naveli u prethodnom bloku):
Ovo je (pretpostavljamo), trenutak kada će se većina čitalaca zapitati (sasvim opravdano): šta su "stanje 4" i "status 200" (i naravno, šta je tačno responseText
)?
Većina uobičajenih zahteva koji se šalju serverima, u praktičnom smislu izvršava se gotovo trenutno, ali, dok se ne završi obrada, zahtev prolazi kroz sledeća stanja:
Nije teško zaključiti da je najviše pažnje potrebno posvetiti prepoznavanju trenutka u kome stanje (readyState
), dostiže vrednost 4 (odnosno, trenutka u kome je prepoznato da je zahtev obrađen), dok se četiri prethodna stanja uglavnom ne proveravaju u kodu.
Pored parametra readyState
(koji označava samo da li je obrada zahteva završena, ili je zahtev "zapeo" na nekom od prethodna četiri stadijuma), potrebno je proveriti i da li je server prepoznao traženi URL i vratio uredno formatirane podatke, ili je pri traženju podataka na serveru (možda) došlo do greške.
U pitanju su dobro poznati statusni kodovi, o kojima smo već pisali (na ovom mestu, podsetićemo se na nekoliko najuobičajenijih statusnih kodova):
Što se tiče parametra responseText
, u pitanju je sav tekstualni sadržaj koji PHP skripta * na koju se XMLHttpRequest
objekat poziva (u našem slučaju, skripta obrada.php
), generiše preko komande echo
.
Povezivanje XMLHttpRequest objekta sa konkretnom PHP skriptom
Komanda open
povezuje XMLHttpRequest
objekat sa konkretnom PHP skriptom.
U primeru koji razmatramo, datoteka obrada.php
je PHP skripta koja će biti korišćena za obradu AJAX zahteva i pokretaće se svaki put kada se serveru uputi zahtev preko XMLHttpRequest
objekta:
Slanje XMLHttpRequest zahteva
Poslednja naredba u bloku koji smo videli na slici #1 (na kojoj je prikazan celokupan kod) ....
.... predstavlja komandu preko koje se (zapravo) serveru šalje zahtev, koji sadrži parametre koji su prethodno definisani (posle čega se od servera dobija odgovor, u tekstualnom obliku, preko polja responseText
objekta xhr
).
Pre nego što se pozabavimo konkretnim primerima upotrebe AJAX-a u izradi chat aplikacije, osvrnućemo se na formate za razmenu podataka izmeću klijenta i servera.
Formati za razmenu podataka
Do sada smo već pominjali da podaci koji nastaju obradom na serveru, do klijenta najčešće dospevaju: ili kao neformatirani tekst, ili u obliku HTML-a, ili u JSON formatu, međutim, poslednje slovo u skraćenici AJAX, ne označava: ni HTML, ni JSON, već (jednu sasvim drugu) skraćenicu - XML.
XML - pomalo zastareo format za razmenu podataka
Extensible Markup Language (skraćeno, XML) je format za razmenu podataka (odnosno - markup jezik), koji - za definisanje objekata putem teksta - koristi:
- sintaksu sličnu HTML-u
- pristup sličan JSON formatu
Na primer, ako bi sledeći JS objekat .....
.... umesto preko JSON formata, bio zapisan u formatu XML, dobili bismo sledeći zapis:
Vidimo da je princip veoma sličan (i razumljiv), ali, na XML sintaksi se nećemo zadržavati iz praktičnih razloga (u današnje vreme, razmena teksta između klijenta i servera pri slanju AJAX zahteva, u najvećem broju slučajeva obavlja se (kao što smo već naveli): ili preko običnog teksta, ili preko HTML-a, ili preko JSON formata).
JSON - savremenije i praktičnije rešenje za razmenu podataka
Budući da je JSON (kako gornji naslov sugeriše), savremenije i praktičnije rešenje za razmenu podataka između klijenta i servera, posvetićemo pažnju metodama koje se koriste za pretvaranje JS objekata u JSON objekte (pri slanju AJAX zahteva), kao i metodama za dekodiranje JSON objekata u PHP-u.
Primer pripreme podataka u JavaScript-u
Sledeći kod (u JavaScript-u):
... pripremiće JSON objekat
.... koji se potom može poslati PHP skripti na dalju obradu.
Primer obrade podataka u PHP-u
Pošto PHP skripta primi poslati JSON objekat, parsiranje se može obaviti preko komande json_decode
....
.... čime se kreira PHP objekat odgovarajućeg sadržaja (a poljima objekta može se pristupati na uobičajeni način):
Primer ovakve razmene podataka, videćemo u nastavku, a sada je vreme da se posvetimo implementaciji chat aplikacije.
Primer korišćenja AJAX-a u izradi chat aplikacije
Da se podsetimo, za chat aplikaciju potrebno je osposobiti sledeće elemente:
- frontend elemente - u vidu polja za slanje novih poruka i prikaz postojećih
- backend - u vidu baze podataka sa podacima o korisnicima i poslatim porukama
- funkciju za slanje novih poruka
- funkciju za periodično ažuriranje spiska razmenjenih poruka (praktično: učitavanje novih poruka koje su poslate u međuvremenu)
Krenimo redom ....
Za početak, dodajte sledeći sadržaj unutar <body>
tagova u skripti index.php
(Navedene id-ove ćemo koristiti u JS kodu.)
Čitanje poruka sa servera
Da bi skripta imala odakle da čita poruke, kreiraćemo na serveru bazu chat
i (unutar baze), tabelu chat_poruke
, sledeće strukture i sadržine:
Strukturu tabele definisaćemo preko SQL koda, a sadržaj možemo "hardkodirati" (da biste odmah mogli da isprobate funkcionalnost skripte za čitanje):
Dodaćemo skriptu citanje_poruka.php
, koja ima sledeći sadržaj (skriptu povezivanje.php
kreirajte po ugledu na skripte za povezivanje kakve smo do sada već koristili):
Ako pokrenete skriptu za čitanje poruka, dobićete u browseru sledeći ispis:
Vidimo da rezultat već uveliko podseća na chat aplikaciju, i sada je samo potrebno pozvati funkciju setInterval
, kojoj se u svojstvu funkcije povratnog poziva predaje funkcija koja šalje AJAX zahteve za čitanje podataka (preko skripte citanje_poruka.php
):
Da pojasnimo:
- na svakih 500ms, * poziva se funkcija
citanjePoruka
- funkcija
citanjePoruka
šalje AJAX zahtev skripticitanje_poruka.php
- skripta
citanje_poruka.php
vraća formatirani spisak poruka (preko komandeecho
) - kada funkcija vezana za događaj
onreadystatechange
prepozna stanje 4 i status 200, poruke će biti ispisane unutar<div>
elementa sa id-omporuke_div
Slanje poruka
Pri slanju poruka, koristićemo malo drugačiji mehanizam za pozivanje AJAX zahteva: radna funkcija za slanje poruka, neće se pozivati periodično (preko funkcije setInterval
), već, preko dugmeta za slanje poruka.
Na primer:
Sadržaj funkcije slanjePoruke
je sledeći:
Slanje poruka PHP skriptama, podrazumeva kreiranje JSON objekta (onako kako smo prethodno videli):
Kada PHP skripta primi poslati paket, sledi dekodiranje preko sledećih funkcija:
json_decode
- kreiranje PHP objekta od primljenog JSON objektamysqli_real_escape_string
ihtmlentities
- 'sanitacija' primljenog podatka (o čemu smo već pisali u prethodnim člancima o PHP-u)trim
- uklanjanje whitespace znakova sa početka i kraja niske
JS funkcija slanjePoruke
, prosleđuje novu poruku skripti dodavanje_poruke.php
(koja u celosti ima sledeći sadržaj):
Poslata poruka pojaviće se u browseru klijenata, posle prvog sledećeg poziva funkcije citanjePoruka
(u praktičnom smislu - naizgled istog trenutka kad je poslata).
Obrada složenijih poruka sa servera
Do sada smo se pretvaranjem teksta u JSON objekte bavili samo u kontekstu poruka koje se šalju u smeru od klijenta prema serveru (kao što ste verovatno već primetili), dok smo u 'obrnutom smeru' slali običan HTML.
Međutim, šta ako se u PHP-u koristi složeni objekat koji sadrži (i) dodatne podatke vezane za izvršavanje upita koji se upućuje bazi ....
.... i potrebno je takav objekat poslati JS skripti kao responseText
?
JSON objekat prvo se "pakuje" u PHP-u, preko komande json_encode
, nakon čega se "šalje" preko komadne echo
....
.... posle čega se primljeni objekat može obraditi u JS-u:
Kao i u ostalim situacijama do sada, JSON priskače u pomoć.
Kako upotpuniti chat aplikaciju?
Šta nedostaje chat aplikaciji koju smo koristili kao primer u članku?
Pre svega (veoma očigledno), sistem za autorizaciju korisnika, koji je ovoga puta (kao što smo već napomenuli), izostavljen zarad preglednosti članka.
Druga stvar (koja možda nije toliko očigledna): može se primetiti da se pri ažuriranju učitavaju sve poruke.
U praksi (u chat aplikacijama sa više (desetina) hiljada poruka), učitavanje svih poruka ne predstavlja optimalan pristup, i bolje rešenje bi bilo - učitavati samo one poruke čiji je id veći od id-a poslednje (do tada) učitane poruke.
Ako rešimo sve što smo naveli, rezultat će biti prava pravcata chat aplikacija. :)
Pored dva pomenuta unapređenja, ako je potrebno da aplikacija bude još dopadljivija, funkcionalnija i modernija, mogu se dodati i delovi koda koji bi prikazivali informacije o tome ko od korisnika je online, kao i o tome da li neko od korisnika trenutno unosi tekst u polje za slanje poruke ("korisnik_x is typing ...."), i sl.
Verujemo da će iskusniji čitaoci (koji su pri tom dobro razumeli do sada izneti sadržaj), rado prihvatiti izazov rešavanja navedenih zadataka.
Za kraj ....
Kroz kratak prikaz 'kostura' jednostavne chat aplikacije, mogli smo uvideti da je način za ažuriranje sadržaja stranice bez ponovnog učitavanja - prilično jednostavan.
Za vežbu, probajte sami da kreirate (neku drugu) web aplikaciju koja koristi AJAX.
Sa naše strane, uskoro ćemo diskusiju o asinhronoj komunikaciju između klijenta i servera, dopuniti člankom koji će za temu imati slanje asinhronih zahteva preko tehnike Fetch API ....