Ultimul subiect pe care il vom aborda inainte sa vedem cum ne ajuta framework-urile JavaScript, este AJAX. AJAX este unul dintre motivele pentru care JavaScript si-a recapatat popularitatea acum cativa ani, odata cu aparitia aplicatiilor web – site-uri care incearca sa reproduca cat mai fidel interfetele aplicatiilor desktop (desigur, aceasta nu se obtine exclusiv cu AJAX, ci si prin manipularea DOM, ca raspuns la interactiunea cu utilizatorul), cum ar fi Gmail, flickr, delicious, etc.
Ceea ce reuseste AJAX sa faca, este sa comunice cu serverul in background si sa faca schimb de date, fara ca utilizatorul sa paraseasca o pagina web. Acronimul AJAX vine de la de la “Asynchronous JavaScript and XML”, nume care incearca sa descrie modul in care functioneaza AJAX: foloseste JavaScript, cererile sunt facute catre server asincron (deci un utilizator poate folosi pagina in timp ce se executa o cerere AJAX) – insa este posibil, dar foarte rar folosit, ca cererile sa fie facute sincron, iar utilizatorul sa nu poata interactiona cu pagina pana la terminarea cererii – iar raspunsul primit este in format XML. De fapt, mai corect spus este ca formatul raspunsului era la inceput aproape exclusiv XML, pentru ca, din ce in ce mai des in ziua de azi, comunicarea client-server prin intermediul AJAX se face schimband date in formatul JSON. De ce? Un motiv ar fi ca dimensiunea cererilor si a raspunsurilor este mult redusa, mai ales pentru cereri/raspunsuri care contin mai putine date, si astfel timpii de cerere si raspuns sunt mai mici, dar probabil cel mai important. asa cum se observa de la numele al carui acronim este JSON: JavaScript Object Notation, este faptul ca formatul JSON este un format nativ al JavaScript. Daca mai tineti minte, in JavaScript puteam crea instante de obiecte generice fie folosind new Object si adaugand membri acestei instante, fie folosind notatia literala JavaScript:
var o = {
"foo": "bar",
"v": [1, 2, 3, 4]
};
Exact pe aceasta notatie se bazeaza JSON, iar mai multe despre sintaxa sa, precum si biblioteci pentru codare/decodare de date in format JSON pentru mai multe limbaje de programare, gasiti pe acest site.
Daca in cazul atasarii ascultatorilor de evenimente aveam de-a face cu mari diferente intre browserele non-IE si IE, de data aceasta singura diferenta este instantierea unui obiect XMLHttpRequest.
Probabil motivul pentru care nu avem de a face cu mari diferente intre IE – restul, este faptul ca Microsoft a introdus XMLHttpRequest pentru prima data (vezi istoria XMLHttpRequest), ca un obiect ActiveX (iar in IE7 a introdus un obiect XMLHttpRequest care incapsuleaza obiectul ActiveX, pentru a putea instantia un XMLHttpRequest intr-un mod cross-browser). Mai tarziu a fost implementat nativ de Firefox/Gecko (incepand cu versiunea 1.0), si la scurt timp de celelalte browsere care respecta standardele (eng. standards-compliant). De mentionat ca XMLHttpRequest nu este inca standardizat, si era inca la stadiul de ciorna la 15 aprilie 2008, atunci cand a fost ultima data modificat documentul care trateaza standardizarea sa – vezi The XMLHttpRequest Object W3C Working Draft.
XMLHttpRequest (sau pe scurt XHR) este nucleul AJAX. cu ajutorul unei instante ale sale, se fac cererile catre server, si tot lui i se ataseaza ascultatori de evenimente pentru a primi raspunsul sau a trata eventualele erori. Cum spuneam, singura diferenta intre browsere este instantierea obiectului, si urmatorul cod ar trebui sa rezolva aceasta (via Wikipedia):
// Provide the XMLHttpRequest class for IE 5.x-6.x:
if( typeof XMLHttpRequest == "undefined")
XMLHttpRequest = function() {
try {
return new ActiveXObject("Msxml2.XMLHTTP.6.0")
} catch(e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP.3.0")
} catch(e) {}
try {
return new ActiveXObject("Msxml2.XMLHTTP")
} catch(e) {}
try {
return new ActiveXObject("Microsoft.XMLHTTP")
} catch(e) {}
throw new Error( "This browser does not support XMLHttpRequest." )
};
Metodele disponibile obiectului XHR sunt:
open(method, URL[, asyncFlag[, userName[, password]]])seteaza adresa la care se va face cererea (URL), metoda folosita (method, de tip string, de obicei “get” sau “post”), daca cererea se va face asincron sau nu (asyncFlag; implicit estetrue, iar daca este setat lafalsecererea se va face sincron), numele de utilizator si parola pentru paginile protejate de username si parola (userName,password– ambele string). Apelul acestei metode nu va deschide conexiunea catre server.setRequestHeader(label, value)primeste doi parametri de tip string si seteaza un header al cererii (de exemplu pentru a setaContent-Lengthvom folosisetRequestHeader("Content-Length", "123")).getResponseHeader(headerLabel)intoarce un string care reprezinta valoarea header-uluiheaderLabel; in mod normal este folosita dupa primirea raspunsului.getAllResponseHeaders()intoarce un string cu toate headerele primite o data cu raspunsul.send(content)trimite serverului continutulcontent. Pentru cereri de tip “get”, trebuie sa specificam parametrii cererii in parametrulURLde laopen(de exemplu,open('get', '/cale/catre/script.php?foo=bar&baz=baz+bat')ar trimite scriptuluiscript.phpparamentrii:foocu valoareabarsibazcu valoareabaz bat– observati ca valorile trebuie sa fie URI-encoded), iar pentru a trimite cererea trebuie sa apelamsend("")sausend(null). Daca avem de-a face cu o cerere de tip POST, va trebui sa setam header-ulContent-Lengthal raspunsului la lungimea continutului trimis. Daca avem continutul intr-o variabila de tip string, ar trebui sa fie suficient unsetRequestHeader("Content-Length", content.length). Aceasta metoda este cea care deschide conexiunea la server.abort()revoca cererea catre server. Atentie insa, este posibil ca cererea sa fi fost primita deja de server si deja procesata, deciabort()nu garanteaza ca va anula efectul cererii. Tot ce face aceasta metoda este sa ignore raspunsul, daca va primi unul, si orice eveniment pe care aceasta l-ar fi declansat.
Proprietatile obiectului XMLHttpRequest sunt urmatoarele:
readyStateeste un intreg care contine informatii despre stadiul in care se afla obiectul. Poate avea 5 valori posibile:- 0 – inseamna ca obiectul a fost creat, dar nu a fost initializat (nu a fost apelat
open) - 1 – inseamna ca s-a apelat
opendar nu sisend - 2 – a fost apelat
send, datele au fost trimise catre server - 3 – s-a primit o parte din datele raspunsului
- 4 – s-a primit tot raspunsul
- 0 – inseamna ca obiectul a fost creat, dar nu a fost initializat (nu a fost apelat
onreadystatechangear trebui sa aiba ca valoare o functie, care va fi apelata de fiecare data cand valoarea luireadyStatese schimba. Aceast membru ar trebui initializat inainte sa apelamsend, altfel este posibil sa pierdem raspunsul (daca obiectul primeste raspunsul inainte caonreadystatechangesa fie initializat).responseTexteste un string care resprezinta raspunsul primit de la server (si este disponibil numai dupa cereadyStatea devenit 4)responseXMLeste un nod DOM, reprezentare a raspunsului primit. Este disponibil numai daca raspunsul primit este in format XML, header-ulContent-Typeestetext/xmlsi numai dupa cereadyStatea devenit 4. Toate metodele disponibile elementelor DOM (despre care am discutat in Manipularea DOM cu JavaScript) sunt valabile pentru acest membrustatusreprezinta status-ul HTTP al raspunsului (de exemplu 200 pentru OK,404pentruNot Found). Orice redirectari din partea serverului ar trebui sa fie manevrate automat de catre browser.statusTextreprezinta mesajul corespunzator status-ului HTTP (de exemplu, dacastatus == 404atuncistatusTextar trebui sa fie"Not Found").
O cerere tipica AJAX ar arata astfel:
var xhr = new XMLHttpRequest();
xhr.open('post', 'script.php');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4)
if (xhr.status >= 200 && xhr.status < 300) {
// coduri HTTP in intervalul [200,300) sunt ok
document.getElementById('raspuns').innerHTML = xhr.responseText;
// sau am putea modifica ierarhia DOM daca raspunsul ar fi XML
if (xhr.responseXML)
alert(responseText.getElementsByTagName('status')[0]);
// am presupus ca in raspunsul xml avem un nod <status>
// care contine status-ul procesarii cererii
// de exemplu: <status>OK<status>
} else {
alert("Eroare");
// in loc sa folosim alert am fi putut schimba innerHTML al unui alt element
// de altfel, folosirea alert nu este chiar ok dpdv al utilizabilitatii
}
};
var continut = "foo=bar&baz=bat";
xhr.setRequestHeader('Content-Length', continut.length);
xhr.send(continut);
//gata!
Cu toate ca AJAX este foarte puternic, exista insa unele neajunsuri.
Unul dintre acestea se refera la functionalitate: cererile AJAX nu se pot face decat catre pagini ale aceluiasi domeniu. Pentru a trece peste acest neajuns, putem folosi pe partea de server rescrieri de adrese care sa faca browserul sa creada ca adresa la care face cererea este din acelasi domeniu (de exemplu, folosind mod_rewrite), sau folosim un proxy-script pentru a trimite cererea la domeniul extern si a intoarce raspunsul scriptului care a pornit cererea AJAX. O alta metoda, care de aceasta data nu mai foloseste AJAX, este folosirea JSONP (detalii aici si aici).
In plus, nu se pot face mai mult de doua cereri concurent catre server, ci trebuie sa asteptam sa primim raspunsul pentru una dintre doua cereri care se petrec la un moment dat, pentru ca a treia sa poata porni. Mai multe despre aceasta si cateva sfaturi, in articolul What I Didn’t Know About XHR.
Apoi, fiindca tot vorbim de interfete web evoluate, folosirea AJAX duce la cateva probleme legate de utilizabilitate: pentru ca toate cererile se fac fara ca utilizatorul sa paraseasca pagina si astfel browserul nu poate informa utilizatorul ca se petrece ceva, au fost dezvoltate tehnici care sa informeze utilizatorul ca se petrece ceva in background – sunt afisate pe ecran mesaje loading, sau sunt folosite gif-uri animate care sa dea de inteles ca se petrece ceva si utilizatorul ar trebui sa astepte. De asemenea, nu mai pot fi folosite butoanele de back/forward ale browserului (desi exista cateva incercari de a repara acest inconvenient, vezi articolul An Evolution of Service tackles the Ajax History paradigm, uneori nici macar nu au sens notiunule de inainte/inapoi).
Dar ca avantajele folosirii AJAX sunt mult mai numeroase decat dezavantajele – cel putin in ziua de azi nu mai trebuie sa incarcam din nou o intreaga pagina doar pentru a acorda un rating unui articol sau unui produs.
Data viitoare, vorbim despre framework-uri JavaScript.
Alte link-uri utile:

The Introducere in AJAX by Interfeţe Web, unless otherwise expressly stated, is licensed under a Creative Commons Attribution-Share Alike 3.0 Romania License.