Aquest article us guiarà a través dels principis bàsics d'AJAX i amb dos pràctics exemples per a anar per feina.
Què és l'AJAX?
El JavaScript asincrònic i XML, (Asynchronous JavaScript and XML, AJAX, en anglès) és un neologisme per a dues potents característiques de navegació que fa anys que existeixen, però que han estat ignorades per molts desenvolupadors web fins a la recent arribada d'aplicacions com Gmail, Google suggest o Google Maps.
Les dues característiques en qüestió són poder:
- Fer sol·licituds al vostre servidor sense haver d'actualitzar la pàgina
- Analitzar i treballar amb documents XML
Primer pas – Com fer una sol·licitud HTTP
Per a fer una sol·licitud HTTP (HTTP request) al servidor fent servir JavaScript, us cal una instància d'una classe que us en proporcioni la funcionalitat. Aquest tipus de classe va introduir-se originalment a l'Internet Explorer com a objecte ActiveX, anomenant-se XMLHTTP
. Més endavant, Mozilla i Safari implementaren una classe, XMLHttpRequest
, que funciona amb els mètodes i propietats de l'objecte original ActiveX de Microsoft.
Com a resultat, per a crear una instància (objecte) de la classe perquè funcioni a tots els navegadors, heu de fer:
if (window.XMLHttpRequest) { // Mozilla, Safari, ... sol·licitud_HTTP = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE sol·licitud_HTTP = new ActiveXObject("Microsoft.XMLHTTP"); }
(L'exemple anterior és una versió simplificada il·lustrativa del codi que s'utilitza per a crear una instància XMLHTTP. Per a un exemple del dia a dia, consulteu el tercer pas d'aquest article.)
Algunes versions dels navegadors Mozilla no funcionaran correctament si la resposta del servidor no té una capçalera MIME XML. Per a satisfer aquesta exigència, podeu utilitzar una crida d'un mètode extra per a ignorar la capçalera que pogués enviar el servidor, si aquesta no fos text/xml
.
sol·licitud_HTTP = new XMLHttpRequest(); sol·licitud_HTTP.overrideMimeType('text/xml');
Tot seguit, cal decidir què voleu fer després de rebre la resposta del servidor a la vostra sol·licitud. En aquest estadi, només cal que especifiqueu a l'objecte de sol·licitud HTTP quina funció de JavaScript processarà la resposta.
Això es fa definint la propietat onreadystatechange
de l'objecte per al nom de la funció de JavaScript que penseu fer sevir, tal com es mostra a continuació:
sol·licitud_HTTP.onreadystatechange = nom_de_la_funció;
Tingueu en compte que no hi ha parèntesis després del nom de la funció i no es passa cap paràmetre. A més, en comptes de donar un nom de funció, podeu utilitzar la tècnica de JavaScript de definir funcions al vol i les accions que en processaran la resposta, tal com es mostra a continuació:
sol·licitud_HTTP.onreadystatechange = function(){ // fes el que calgui };
Després d'haver declarat allò que passarà després de rebre la resposta, cal fer-ne la sol·licitud. Heu de cridar els mètodes open()
i send()
de la classe de sol·licitud HTTP, tal com es mostra a continuació:
sol·licitud_HTTP.open('GET', 'https://www.exemple.org/algun.fitxer', true); sol·licitud_HTTP.send(null);
- El primer paràmetre de la crida a
open()
és el mètode de sol·licitud HTTP – GET, POST, HEAD o qualsevol altre mètode que ja vulgueu utilitzar i funcioni al vostre servidor. Escriviu-lo en majúscules atès que és un estàndard de l'HTTP; per altra banda, alguns navegadors (com el Firefox) podrien no processar la sol·licitud. Per a més informació dels mètodes de sol·licitud HTTP, podeu consultar les especificacions W3C - El segon paràmetre és l'URL de la pàgina que esteu sol·licitant. Com a mesura de seguretat, no podeu cridar a pàgines en dominis de tercers. Assegureu-vos que utilitzeu el nom de domini exacte en totes les vostres pàgines o tindreu un error de «permís denegat» quan crideu a open(). Una trampa comuna és accedir al vostre lloc web amb domini.tld, però intentar cridar les pàgines amb www.domini.tld.
- El tercer paràmetre defineix si la sol·licitud és asincrònica. Si és així,
TRUE
, l'execució de la funció de JavaScript continuarà mentre la resposta del servidor no hagi arribat. Aquesta és l'A d'AJAX.
El paràmetre al mètode send()
pot ser qualsevol dada que vulgueu enviar al servidor si s'envia la sol·licitud amb POST. Les dades cal que siguin de la forma d'una cadena de consulta com aquesta:
nom=valor&un_altre_nom=un_altre_valor&i_així=anar_fent
Tingueu en compte que si voleu enviar dades amb POST, heu de canviar el tipus MIME de la sol·licitud utilitzant la següent línia:
sol·licitud_HTTP.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
Si no ho feu així, el servidor rebutjarà les dades que hi hàgiu enviat.
Segon pas – Gestionar la resposta del servidor
Recordeu que quan envieu la sol·licitud, també proporcioneu el nom de la funció JavaScript destinada a gestionar-ne la resposta.
sol·licitud_HTTP.onreadystatechange = nom_de_la_funció;
Observem què hauria de fer aquesta funció. Primer, cal que comprovi l'estat de la sol·licitud. Si aquesta té el valor 4, vol dir que s'ha rebut una resposta total del servidor i podeu continuar processant-la.
if (sol·licitud_HTTP.readyState == 4) { // tot va bé, s'ha rebut la resposta } else { // encara no està preparada }
La llista sencera de valors d'estat, readyState
, és la següent:
- 0 (sense inicialitzar)
- 1 (s'està carregant)
- 2 (carregat)
- 3 (interactiu)
- 4 (complerta)
(Font)
A continuació, cal que comproveu el codi d'estat de la resposta de servidor HTTP. Tots els codis possible es llisten al lloc del W3C. Per als nostres objectius, només ens interessa la resposta 200 OK
.
if (sol·licitud_HTTP.status == 200) { // perfecte! } else { // hi ha hagut algun problema amb la sol·licitud // per exemple, la resposta podria ser uns codis de resposta // 404 (Not Found) o 500 (Internal Server Error) }
Després d'haver comprovat l'estat de la sol·licitud i el codi d'estat HTTP de la resposta, heu de decidir què voleu fer amb les dades que el servidor us ha enviat. Teniu dues opcions per a accedir a les dades:
-
sol·licitud_HTTP.responseText
– retornarà la resposta del servidor com una cadena de text. -
sol·licitud_HTTP.responseXML
– retornarà la resposta com un objecte document XML,XMLDocument
, que podeu recórrer utilitzant les funcions DOM de JavaScript.
Tercer pas – Un exemple simple
Posem-ho tot junt i fem una sol·licitud HTTP simple. El nostre codi JavaScript sol·licitarà un document HTML, prova.html
, que conté el text «Açò és un text.» i llavors notificarà, alert()
, els continguts del fitxer prova.html
.
<script type="text/javascript" language="javascript"> function fes_sol·licitud(url) { var sol·licitud_HTTP = false; if (window.XMLHttpRequest) { // Mozilla, Safari,... sol·licitud_HTTP = new XMLHttpRequest(); if (sol·licitud_HTTP.overrideMimeType) { sol·licitud_HTTP.overrideMimeType('text/xml'); // Vegeu la nota a sota } } else if (window.ActiveXObject) { // IE try { sol·licitud_HTTP = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { sol·licitud_HTTP = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {} } } if (!sol·licitud_HTTP) { alert('S\'abandona :( No es pot crear una instància d'XMLHTTP'); return false; } sol·licitud_HTTP.onreadystatechange = function() { notifica_continguts(sol·licitud_HTTP); }; sol·licitud_HTTP.open('GET', url, true); sol·licitud_HTTP.send(null); } function notifica_continguts(sol·licitud_HTTP) { if (sol·licitud_HTTP.readyState == 4) { if (sol·licitud_HTTP.status == 200) { alert(sol·licitud_HTTP.responseText); } else { alert('Hi ha hagut un problema amb la sol·licitud.'); } } } </script> <span style="cursor: pointer; text-decoration: underline" onclick="fes_sol·licitud('prova.html')"> Fes una sol·licitud </span>
En aquest exemple:
- L'usuari fa un clic a l'enllaç «Fes una sol·licitud»;
- Açò crida a la funció
fes_sol·licitud()
amb un paràmetre – el nomprova.html
d'un fitxer HTML en el mateix directori; - Es fa la sol·licitud i llavors (
onreadystatechange
) l'execució es passa anotifica_continguts()
; -
notifica_continguts()
comprova si la resposta s'ha rebut, i si és correcta, llavorsalert()
notifica dels continguts al fitxerprova.html
.
Podeu provar l'exemple ací i veure el fitxer de prova també ací.
Nota: La línia sol·licitud_HTTP.overrideMimeType('text/xml');
anterior donarà errors a la consola de Javascript al Firefox 1.5b tal com es documenta a https://bugzilla.mozilla.org/show_bug.cgi?id=311724 si la pàgina que es crida per XMLHttpRequest no és un XML vàlid (p.ex., si és text net).
Si obteniu un error de sintaxi (Syntax Error) o de mal format (Not Well Formed Error) en el navegador, i no esteu intentant carregar una pàgina XML per XMLHttpRequest, suprimiu aquesta línia del codi.
Nota 2: si envieu una sol·licitud a un codi que retorni XML, en comptes d'un fitxer XML estàtic, heu d'especificar-ne algunes capçaleres de resposta si la vostra pàgina ha de funcionar amb l'Internet Explorer a més d'amb el Mozilla. Si no hi definiu la capçalera, Content-Type: application/xml
, l'IE llançarà un error de Javascript 'Object Expected' després de la línia des d'on intenteu accedir a un element XML. Si no hi definiu una capçalera, Cache-Control: no-cache
, el navegador emmagatzemarà a la memòria cau la resposta i no tornarà mai a trametre la sol·licitud, fent llavors que la depuració sigui tot un repte.
Nota 3: si la variable sol·licitud_HTTP s'utilitza globalment, aquelles funcions «competidores» que cridin a fes_sol·licitud() poden anul·lar-se unes a les altres, provocant doncs una condició de cursa. En declarar sol·licitud_HTTP com una variable local a la funció i passar-la a la funció notifica_continguts() ho evita.
Note 4: Per a registrar la funció de resposta onreadystatechange, no podeu tenir cap argument:
sol·licitud_HTTP.onreadystatechange = function() { notifica_continguts(sol·licitud_HTTP); }; //1 (sol·licitud simultània) sol·licitud_HTTP.onreadystatechange = notifica_continguts(sol·licitud_HTTP); //2 (no funciona) sol·licitud_HTTP.onreadystatechange = notifica_continguts; //3 (variable global)
El mètode 1 us permet tenir diferent sol·licituds fetes simultàniament, el 2 no funciona, i el 3 s'utilitza si sol·licitud_HTTP és una variable global.
Quart pas – Treballant amb la resposta XML
En l'anterior exemple, després que es rebés la resposta a la sol·licitud HTTP, vam fer servir la propietat reponseText
de l'objecte de sol·licitud i contenia els continguts del fitxer prova.html
. Provem-ho ara amb la propietat responseXML
.
Comencem creant un document XML vàlid, que sol·licitarem més endavant. El document (prova.xml) conté el següent:
<?xml version="1.0" ?> <root> Açò és una prova. </root>
A la seqüència, només cal que canviar-hi la línia de sol·licitud per:
... onclick="fes_sol·licitud('prova.xml')"> ...
Llavors a notifica_continguts()
cal que reemplacem la línia amb alert()
d'alert(sol·licitud_HTTP.responseText);
per:
var document_xml = sol·licitud_HTTP.responseXML; var node_arrel = document_xml.getElementsByTagName('root').item(0); alert(node_arrel.firstChild.data);
D'aquesta forma prenem l'objecte XMLDocument
donat per responseXML
i utilitzem els mètodes DOM per a accedir a algunes dades que es troben al document XML. Podeu veure-ho a prova.xml
ací i la seqüència de prova actualizada ací.
Per a més informació dels mètodes DOM, consulteu els documents de la implementació DOM de Mozilla.