nav_dugme codeBlog codeBlog
  • početna Početna stranica
  • Sačuvani članci Sačuvani članci
  • Članci
     (spisak)
  • Kontakt
Povratak na vrh stranice

Info & povezani članci Info o članku - dugme

Info

trejler_sat Datum objave: 24.06.2021.

trejler_dokument Jezici: JavaScript,
PHP

trejler_teg_narandzasti Težina: 7/10

JavaScript
PHP
ajax
MySql
internet
http
http statusni kodovi
baze podataka
upit
get
json
web server
localhost
backend
teorija
tutorijali

Povezani članci

Asinhrono programiranje u JavaScriptuUvod u Fetch APIUvod u PHP i back-end programiranjeUvod u Node.jsJSON - tekstualni format za razmenu podatakaUvod u relacione baze podataka i SQLCallback funkcije i lambda izraziHTTP statusni kodoviPokretanje lokalnog web serveraASCII, Unicode i UTF - Predstavljanje znakova na računarima
Svi članci
What one programmer can do in one month, two programmers can do in two months.
Frederick P. Brooks

Uvod u AJAX (Asynchronous JavaScript And XML)

Facebook LinkedIn Twitter Viber WhatsApp E-mail
zoom_plus zoom_minus bookmark
početna > Članci > Teorija

Uvod

Termin AJAX (skraćeno od "Asynchronous JavaScript And XML"), označava 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 (najčešće) 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
  • back-end chat aplikacije (najčešće/"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 se na ekranu svih korisnika koji učestvuju u chat-u (zajedno sa prethodno poslatim porukama)

U praksi (pored osnovnih zahteva koje smo naveli), chat aplikacije podrazumevaju i upotrebu korisničkih naloga i mehanizama za autorizaciju korisnika, i (naravno), pri slanju poruka takođe se podrazumeva da sadržaj svake poruke podleže različitim proverama (u smislu sprečavanja prosleđivanja nedozvoljenih specijalnih znakova koji su deo SQL sintakse i sl).

Zarad preglednosti, detaljniju diskusiju po navedenim pitanjima ostavićemo za neku drugu priliku i ovoga puta ćemo se zadržati samo na temama koje se direktno tiču slanja i automatskog ažuriranja poruka u polju za prikaz.

Takođe, napomenimo da je izrada chat aplikacije (čak i onih delova koje nećemo implementirati u ovom članku), mnogo jednostavniji zahvat nego što se obično očekuje, kao što ćete i videti u nastavku (ili, kraće - ne bojte se, nije mnogo teško). 🙂

Kada sagledamo listu koju smo prethodno naveli (na početku odeljka), deluje 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, ** 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).

* Dakle: nema automatskog osvežavanja naknadno.

** U slučaju pojave grešaka u obradi zahteva: umesto HTML-a i drugih traženih sadržaja, server šalje klijentu odgovarajući statusni kod.

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, JavaScript (koji se pokreće u web browserima), omogućava 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), nije ni iz daleka "previše komplikovan", i samo preostaje da se upoznamo sa tehnikalijama, i da sve povežemo u funkcionalnu celinu.

Pre toga, mala digresija ....

Kratak istorijat web tehnologija

Automatsko osvežavanje (tj. ažuriranje) HTML elemenata o kome govorimo u članku, jeste nešto na šta su korisnici interneta odavno navikli, ali, nije uvek bilo automatskog osvežavanja.

Da bismo dodatno 'postavili stvari u perspektivu', osvrnućemo se ukratko na tok razvoja web tehnologija, koji se (kolokvijalno) može podeliti na sledećih nekoliko perioda:

  • "web 1" (cca. 1990- ) - statičke web stranice na čiji sadržaj korisnici nemaju uticaja ("read-only web")
  • "web 2" (cca. 2000- ) - dinamičke web stranice koje koriste AJAX (i druge tehnologije), i omogućavaju interakciju korisnika sa web serverima (forumi i društvene mreže sa sadržajima i komentarima koje generišu sami korisnici, web aplikacije koje se pokreću u browserima, blogovi, video platforme, online prodavnice i sl)
  • "web 3" (cca. 2020- ) - sve veće prisustvo i primena veštačke inteligencije i blockchain tehnologija, virtuelna stvarnost, proširena stvarnost ("augmented reality") i sl.

Tehnologije koje spadaju u kategoriju "web 2" počele su da se pojavljuju još na prelasku između 20. i 21. veka (neke od njih, već i sredinom devedesetih godina), ali, za prave su uzele maha između cca. 2005. i 2010. sa pojavom mrežnih servera i klijentskih računara koji su (konačno) postali dovoljno snažni da omoguće legitimnu upotrebu AJAX-a i drugih pomenutih tehnologija (naravno, "web 2" tehnologije su prisutne i dan-danas, baš kao što i dalje postoji i veći broj statičkih "web 1" sajtova i sl).

AJAX - osnovne postavke

Kao što smo nagovestili još na početku, "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

* Pre nego što se posvetimo AJAX zahtevima, napomenimo (za svaki slučaj, iako pretpostavljamo da je do sada već postalo očigledno): AJAX nije programski jezik - kako se ponekad misli - već samo 'lepa i zvučna skraćenica' koju je američki programer Džesi Džejms Garet skovao početkom 2005 (AJAX: A New Approach to Web Applications).

Takođe se može primetiti (u širem kontekstu), da skraćenica koja u prevodu znači "Asinhroni Javascript i XML", ne bi imala posebno značenje sama po sebi, da se u praksi ne odnosi na mehanizam koji je prilično skladan, funkcionalan i (naravno) svrsishodan.

** Iako poslednje slovo u skraćenici AJAX upućuje na format XML, podaci se tipično razmenjuju u JSON formatu (više o svemu u nastavku).

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:

  • za događaj onreadystatechange vezuje 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 ....

		
function ajaxProba() {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
            let infoDiv       = document.getElementById("info_div");
            infoDiv.innerHTML = xhr.responseText;
        }
    };

    xhr.open("GET", "./obrada.php", true);
    xhr.send();
}
		
	
Slika 1. - Opšti oblik funkcije za slanje zahteva preko objekta klase XMLHttpRequest.

.... posle čega ćemo detaljno analizirati delove.

Provera stanja zahteva

Neimenovana funkcija povratnog poziva, koja se povezuje sa događajem onreadystatechange ....

		
xhr.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
        let infoDiv       = document.getElementById("info_div");
        infoDiv.innerHTML = xhr.responseText;
    }
};
		
	
Slika 2. - Događaj onreadystatechange, za koji je vezana funkcija preko koje se praktično obavlja komunikacija između PHP-a i JS-a.

.... 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):

		
let infoDiv       = document.getElementById("info_div");
infoDiv.innerHTML = xhr.responseText;
		
	
Slika 3. - Dodela HTML-a koji je primljen iz PHP skripte, elementu sa id-om "info_div".

Ovo je (pretpostavljamo), trenutak kada će se većina čitalaca zapitati (sasvim opravdano): šta su "stanje 4" i "status 200" (i šta je tačno responseText)?

Za čitaoce koji su upućeni u HTTP statuse, napominjemo da je status 200, "ono što i inače predstavlja pri učitavanju stranica" (a verovatno naslućujete i šta je readyState 4), međutim, nastavljamo sa proučavanjem koda 'po redu' ....

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:

		
readyState:

0 - zahtev (još uvek) nije poslat
1 - zahtev je poslat (ali nije primljen)
2 - zahtev je primljen (ali nije uzet u obradu)
3 - zahtev je uzet u obradu (ali obrada nije završena)
4 - obrada zahteva je završena
		
	
Slika 4. - Stanja kroz koja prolazi XMLHttpRequest zahtev.

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 HTTP statusni kodovi o kojima smo već pisali, ali, podsetićemo se (ukratko) na nekoliko najuobičajenijih statusnih kodova:

		
-Uspešan prijem podataka:

200 - status OK - uspešno primljeni podaci

-Neuspešan prijem podataka:

403 - neodgovarajući podaci za autorizaciju
404 - traženi podatak ne postoji na serveru
503 - server nije u stanju da odgovori
		
	
Slika 5. - Nekoliko najuobičajenijih HTTP statusa.

Što se tiče parametra responseText, u pitanju je sav tekstualni sadržaj koji PHP skripta na koju se XMLHttpRequest objekat poziva, * generiše preko komande echo (u našem slučaju, 'AJAX zahtev' dobija tekstualni odgovor od skripte obrada.php),.

* Zarad opšte informisanosti, napomenimo da ne mora biti "PHP skripta".

U članku koristimo PHP skripte, međutim, u opštem smislu, objekat klase XMLHttpRequest se zapravo obraća određenom URL-u iza koga može biti PHP skripta, ali - može biti i bilo kakav drugi back-end (realizovan preko neke druge back-end tehnologije, kao što je npr. Node.JS); naravno - pod uslovom da su pozadinski procesi u stanju da na prikladan način odgovore na zahtev koji se šalje (i proslede pravilno formatiran tekstualni odgovor).

Povezivanje XMLHttpRequest objekta sa konkretnom PHP skriptom

Komanda open povezuje objekat klase XMLHttpRequest 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:

		
xhr.open("GET", "./obrada.php", true);
		
	
Slika 6. - Komanda open, za povezivanje XMLHttpRequest zahteva sa PHP skriptom.

Slanje XMLHttpRequest zahteva

Poslednja naredba u bloku koji smo videli na slici #1 (na kojoj je prikazan celokupan kod) ....

		
xhr.send();
		
	
Slika 7. - Slanje XMLHttpRequest zahteva.

.... 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).

Ponekad, kao što ćemo videti na primeru AJAX funkcije za slanje poruka u chat aplikaciji, JS skripta od PHP skripte neće dobiti nikakav tekstualni odgovor - što je sasvim u redu (detaljnije o svemu, u nastavku).

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

XML (skraćeno od "Extensible Markup Language") je format za razmenu podataka (odnosno markup jezik), sa sledećim glavnim odlikama:

  • sintaksa je slična HTML-u
  • opšti pristup je sličan JSON formatu

Na primer, ako bi sledeći JS objekat .....

		
let osoba = {
	ime:             "Petar",
	prezime:         "Petrović",
	godina_rodjenja: 1979
};
		
	
Slika 8. - JSON objekat (koji ćemo u sledećem koraku pretvoriti u XML).

.... umesto preko JSON formata, bio zapisan u formatu XML, dobili bismo sledeći zapis:

		
<osoba>
	<ime>Petar</ime>
	<prezime>Petrović</prezime>
	<godina_rodjenja>1979</godina_rodjenja>
</osoba>
		
	
Slika 9. - XML zapis JSON objekta sa prethodne slike.

Vidimo da je opšti princip relativno sličan (i sasvim razumljiv), ali, nećemo se zadržavati na XML sintaksi - 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 se obavlja (kao što smo već pomenuli): ili preko običnog teksta, ili preko HTML-a, ili preko JSON formata).

Prosto rečeno: format XML nije manjkav, ali, ponešto je prevaziđen, i (u očima većine programera), manje elegantan u odnosu na JSON.

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) ....

		
let osoba = {
	ime:             "Petar",
	prezime:         "Petrović",
	godina_rodjenja: 1979
};

let poruka_paket_json = JSON.stringify(osoba);
		
	
Slika 10. - Komanda stringify, za pretvaranje JS objekta u JSON objekat.

... poslužiće za pripremu JSON objekta ....

		
{
	"ime":             "Petar",
	"prezime":         "Petrović",
	"godina_rodjenja": 1979
}
		
	
Slika 11. - JSON objekat, kao posrednik između JS objekta sa prethodne slike i PHP-a.

.... koji se potom može poslati PHP skripti, zarad dalje obrade.

Primer obrade podataka u PHP-u

Nakon što PHP skripta primi poslati JSON objekat, parsiranje se obavlja preko funkcije json_decode ....

		
<?php
	if (!isset($_GET["p"])) {
		// naredbe koje treba pozvati ako
		// podaci NISU prosleđeni ....
	}

	$osoba = json_decode($_GET["p"], false);
?>
			
	
Slika 12. - PHP komanda json_decode, za kreiranje PHP objekta preko podataka iz primljenog JSON objekta.

.... pri čemu je rezultat obrade - PHP objekat odgovarajućeg sadržaja:

		
$osoba->ime             // Petar
$osoba->prezime         // Petrović
$osoba->godina_rodjenja // 1979
		
	
Slika 13. - Polja PHP objekta koji je nastao dekodiranjem primljenog JSON objekta.

Nakon parsiranja JSON objekta, poljima PHP objekta pristupa se na uobičajeni način.

Primer razmene podataka preko JSON objekata videćemo nešto kasnije, a sada je vreme da počnemo da implementiramo chat aplikaciju.

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

		
<div id='poruke_div'>
	<!-- Poruke -->
</div>
<input id='nova_poruka_tekst' type='text' />

<button onclick='slanjePoruke()'>SLANJE PORUKE</button>
		
	
Slika 14. - Struktura nekoliko HTML elemenata, koje ćemo koristiti kao polja za slanje i prikaz poruka u chat aplikaciji.

(Navedene id-ove koristićemo 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:

		
id | id_korisnika | korisnicko_ime | tekst_poruke  | vreme
------------------------------------------------------------------------
 1 | 112          | joca21         | Ćao svima! :) | 2021-06-19 18:54:14
 2 | 237          | peraX          | Šta ima?      | 2021-06-19 18:54:19
 3 | 125          | maja_bg        | Poyy          | 2021-06-19 18:54:25
		
	
Slika 15. - Struktura i sadržaj tabele chat_poruke.

Strukturu tabele definisaćemo preko SQL koda, a sadržaj možemo "hardkodirati" (da biste odmah mogli da isprobate funkcionalnost skripte za čitanje):

		
CREATE TABLE chat_poruke (
    id int not null AUTO_INCREMENT PRIMARY KEY,
    id_korisnika int not null,
    korisnicko_ime varchar(255) not null,
    tekst_poruke text not null,
    vreme datetime not null    
);

INSERT INTO chat_poruke
	(id_korisnika, korisnicko_ime, tekst_poruke, vreme)
VALUES
    (112, 'joca21', 'Ćao svima! :)', '2021-06-19 18:54:14'),
    (237, 'peraX', 'Šta ima?', '2021-06-19 18:54:19'),
    (125, 'maja_bg', 'Poyy', '2021-06-19 18:54:25')
		
	
Slika 16. - SQL kod za kreiranje strukture i popunjavanje sadržaja tabele chat_poruke sa prethodne slike.

Možete (naravno), 'na brzaka' implementirati i nekakav priručni mehanizam za slanje poruka (pre nego što to, u nastavku, zajedno uradimo 'zvanično').

Dodaćemo skriptu citanje_poruka.php, koja ima sledeći sadržaj (pomoćnu skriptu povezivanje.php kreirajte po ugledu na skripte za povezivanje kakve smo do sada već koristili):

		
<?php
	require_once("povezivanje.php");

	$upit     = "SELECT * FROM chat_poruke ORDER BY id ASC";
	$rezultat = mysqli_query($veza, $upit);

	$odgovor = "";
	
	while ($red = mysqli_fetch_assoc($rezultat)) {
		$odgovor .= "<div class='poruka_red'>";
		$odgovor .= "<b>" . $red['korisnicko_ime'] . "</b>: ";
		$odgovor .= $red['tekst_poruke'] . " (<font color='#27b'>";
		$odgovor .= $red['vreme'] . ")</font>";
		$odgovor .= "</div>";
	}

	echo $odgovor;
?>
		
	
Slika 17. - PHP skripta citanje_poruka.php, preko koje se čita sadržaj tabele chat_poruke.

Ako pokrenemo skriptu za čitanje poruka, dobićemo u browseru sledeći ispis:

joca21: Ćao svima! (2021-03-19 18:54:14)
peraX: Šta ima? (2021-03-19 18:54:19)
maja_bg: Poyy (2021-03-19 18:54:25)

Slika 18. - Rezultat izvršavanja PHP skripte citanje_poruka.php.

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):

		
setInterval(citanjePoruka, 500);

function citanjePoruka() {
	const xhr = new XMLHttpRequest();

	xhr.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
	       
	       document.getElementById("poruke_div").innerHTML = xhr.responseText;
	    }
	};

	xhr.open("GET", "./citanje_poruka.php", true);
	xhr.send();
}
		
	
Slika 19. - AJAX skripta za čitanje poruka preko prethodno opisane PHP skripte.

Da pojasnimo:

  • na svakih 500ms * poziva se funkcija citanjePoruka
  • funkcija citanjePoruka šalje AJAX zahtev skripti citanje_poruka.php
  • skripta citanje_poruka.php vraća formatirani spisak poruka (preko komande echo)
  • kada funkcija vezana za događaj onreadystatechange prepozna stanje 4 i status 200, poruke se ispisuju unutar <div> elementa sa id-om poruke_div

* Izabrani interval (500ms), u praksi predstavlja dobru ravnotežu: sa jedne strane poželjno je da aplikacija deluje kao da učitava poruke trenutno, dok, sa druge strane, nije preporučljivo (ni iz daleka!), da se server (pre)optereti nepotrebnim zahtevima.

Primera radi, ako bi se interval očitavanja povećao na 1000ms, ponekad bi bilo moguće primetiti vremenski razmak između slanja poruke i prikaza poruke u prozoru, dok, ako bi se vrednost primetno smanjila (recimo, na 100ms), verovatno ne bismo primetili nikakvu razliku (tj, "promenu na bolje") u odnosu na 500ms - pri čemu bi opterećenje servera bilo znatno veće.

Slanje poruka

Pri slanju poruka, koristićemo nešto 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:

		
<button onclick='slanjePoruke()'>SLANJE PORUKE</button>
		
	
Slika 20. - HTML kod za definisanje dugmeta preko koga se pokreće skripta za slanje novih poruka.

Sadržaj funkcije slanjePoruke je sledeći:

		
function slanjePoruke() {
	
	let tekst_poruke = document.getElementById("nova_poruka_tekst").value;
	tekst_poruke     = tekst_poruke.trim();
	tekst_poruke     = tekst_poruke.replace(/"/g, "'");
	tekst_poruke     = encodeURIComponent(tekst_poruke);

	if (tekst_poruke.length == 0) {
		document.getElementById("nova_poruka_tekst").value = "";
		return;
	}
	
	const xhr = new XMLHttpRequest();

	xhr.onreadystatechange = function() {
	    if (this.readyState == 4 && this.status == 200) {
	    	document.getElementById("nova_poruka_tekst").value = "";
	    }
	};

	let poruka_paket = {
		"tekst_poruke" : tekst_poruke
	};
	
	let poruka_paket_json = JSON.stringify(poruka_paket);
		
	xhr.open("GET", "slanje_poruke.php?p=" + poruka_paket_json, true);
	xhr.send();
}
		
	
Slika 21. - AJAX funkcija za slanje novih poruka, koja prosleđuje podatke PHP skripti slanje_poruke.php.

Slanje poruka PHP skriptama, podrazumeva kreiranje JSON objekta (onako kako smo prethodno videli):

		
let poruka_paket = {
	"tekst_poruke" : tekst_poruke
};

let poruka_paket_json = JSON.stringify(poruka_paket);
		
	
Slika 22. - JavaScript kod za pripremu JSON objekta koji će biti poslat PHP skripti.

Kada PHP skripta primi poslati paket, sledi dekodiranje preko sledećih funkcija:

  • json_decode - kreiranje PHP objekta od primljenog JSON objekta
  • mysqli_real_escape_string i htmlentities - '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):

		
<?php
	include_once('povezivanje.php');
	
	$poruka_paket = json_decode($_GET["p"], false);
	$tekst_poruke = $poruka_paket->tekst_poruke;
	$tekst_poruke = mysqli_real_escape_string($veza, $tekst_poruke);
	$tekst_poruke = htmlentities($tekst_poruke);
	$tekst_poruke = trim($tekst_poruke);
	
	if (empty($tekst_poruke)) {
		exit();
	}
	
	$datum_poruke    = date("Y-m-d");
	$vreme_poruke    = date("H:i:s");
	$vremeDB         = "$datum_poruke $vreme_poruke";
	
	// Ovoga puta, zarad preglednosti, izostavićemo delove koda
	// za autorizaciju, i unapred ćemo definisati id korisnika i
	// korisničko ime

	$id_korisnika    = 419;
	$korisnicko_ime  = "cane15";
	
	$upit     = "INSERT INTO chat_poruke
	                 (id_korisnika, korisnicko_ime, tekst_poruke, vreme)
	             VALUES
	                 ('$id_korisnika', '$korisnicko_ime',
	                  '$tekst_poruke', '$vremeDB')";

	$rezultat = mysqli_query($veza, $upit);
	
	if (!$rezultat) {
		echo "Greška pri slanju poruke!";
	}
?>
		
	
Slika 23. - PHP skripta za upis nove poruke u bazu podataka.

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 ....

		
<?php
	class Odgovor {
		public $tekst,
		       $status,
		       $poruka_o_gresci;

		/*
			tekst            - poruka koja se šalje klijentu u slučaju
			                   da nije bilo grešaka u obradi
			
			status           - true  - nije bilo grešaka u obradi
			                 - false - bilo je grešaka u obradi

			$poruka_servera - poruka servera, u slučaju da dođe
			                  do greške u obradi
		*/

		function __construct($tekst, $status, $poruka_o_gresci) {
			$this->tekst           = $tekst;
			$this->status          = $status;
			$this->poruka_o_gresci = $poruka_o_gresci;
		}
	}

	if ($rezultat) {
		$red = mysqli_fetch_assoc($rezultat);
		$odgovor = new Odgovor($red['kolona_3'], true, "");
	}
	else {
		$poruka_servera = "Greška u obradi zahteva!";
		$odgovor = new Odgovor("", false, $poruka_servera);
	}	
?>
		
	
Slika 24. - PHP skripta sa objektom koji sadrži tekstualne podatke (budući da ne koristimo komandu echo, skripta za sada ne prosleđuje nazad podatke do JS-a).

.... 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:

		
<?php
	$poruka_za_js = json_encode($odgovor);
	echo $poruka_za_js;
?>
		
	
Slika 25. - PHP kod za pripremu JSON objekta koji se prosleđuje AJAX skripti (preko komande echo).

Kada poslati objekat dospe u JS skriptu, može se obraditi preko već poznate metode parse:

		
let json_iz_php_a = JSON.parse(this.responseText);

let ispis = json_iz_php_a['tekst'] + "<br>" + 
            json_iz_php_a['poruka_o_gresci'] + "<br>" +
            json_iz_php_a['status'];

document.getElementById("poruke_div").innerHTML = 
		
	
Slika 26. - Obrada primljenog JSON objekta (koji je prosleđen iz PHP skripte i sadrži tekstualne informacije).

Kao i u mnogim drugim 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 omogućili prikaz 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 (ili makar relativno 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 ....

Autor članka Nikola Vukićević Za web portal codeblog.rs
Napomena: Tekstovi, slike, web aplikacije i svi ostali sadržaji na sajtu codeblog.rs (osim u slučajevima gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog pismenog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook LinkedIn Twitter Viber WhatsApp E-mail
početna > Članci > Uvod u AJAX (Asynchronous JavaScript And XML)
codeBlog codeBlog
Sajt posvećen popularizaciji kulture i veštine programiranja.
Napomena: Tekstovi i slike na sajtu codeblog.rs (osim u slučajevima, gde je drugačije navedeno) predstavljaju intelektualnu svojinu autora sajta codeblog.rs i zabranjeno je njihovo korišćenje na drugim sajtovima i štampanim medijima, kao i bilo kakvo drugo korišćenje u komercijalne svrhe, bez eksplicitnog odobrenja autora.
© 2020-2026. Sva prava zadržana.
Facebook - logo
Instagram - logo
LinkedIn - logo
Twitter - logo
E-mail
Naslovna
   •
Uslovi korišćenja
   •
Obaveštenja
   •
FAQ
   •
Kontakt