Como me está picando la curiosidad de entender esto de AJAX, he decidido echar un vistazo a algún tutorial básico sobre AJAX y entender cómo demonios se puede recorrer un documento XML con Javascript, teniendo en cuenta que implementar y enviar un parser de XML en Javascript al navegador es muy costoso.

El secreto, que yo no conocía, es que se ha implementado, en los navegadores más utlizados (Internet Explorer, Firefox, etc.), un objeto XMLHttpRequest que se encarga de todo esto. Es decir, que basta con crear una instancia de este objeto para poder realizar peticiones HTTP al servidor en XML y recibir sus respuestas de modo asíncrono o síncrono.

Aunque siempre he criticado a Microsoft por ser unos copiones y por crear productos cerrados para atar al cliente, esta vez debo darles la enhorabuena por ser los primeros en crear este objeto que va a dar lugar a una nueva era de aplicaciones web nunca vistas hasta ahora. De todas formas, todavía debo seguir criticándoles su manía de crear tecnologías exclusivas para su navegador Internet Explorer, ya que la forma de crear instancias de este objeto es exclusivo para sistemas Windows, y por tanto diferente de otros navegadores que tratan de ser multiplataforma.

Comencemos.

La forma de crear una instancia de este objeto en cualquier navegador es:

var req = new XMLHttpRequest();

y en Microsoft Internet Explorer depende de ActiveX:

var req = new ActiveXObject("Microsoft.XMLHTTP");

Métodos

Los métodos de un objeto XMLHttpRequest son los siguientes:

  • abort(): Aborta la petición actual.
  • getAllResponseHeaders(): Devuelve todas las cabeceras (etiquetas y valores) como un string.
  • getResponseHeader("headerLabel"): Devuelve el valor de la cabecera etiquetada como headerLabel.
  • open("method", "URL"[, asyncFlag[, "userName"[, "password"]]]): Abre una conexión a una URL, con un método HTTP (get o post), y otros parámetros opcionales.
  • send(content): Envía la petición. Suele ser un String o un objeto DOM
  • setRequestHeader("label", "value"): Crea un par etiqueta/valor para ser enviado en la cabecera de la petición.

Los métodos más importantes son open y send.

El método open prepara la conexión con el servidor. Para ello se le pasa la URL - absoluta o relativa - y el método HTTP, get o post, según si se recibe o se envía datos.

Por defecto, la conexión es asíncrona, es decir, la petición se realiza al servidor y el usuario puede seguir interactuando con la página sin que se dé cuenta. Si se quiere una conexión síncrona, se debe utilizar el parámetro asyncFlag=false, lo que hará que el navegador quede parado hasta recibir la respuesta del servidor. Esto es peligroso porque puede dejar colgado al navegador si hay algún tipo de error, por lo que se aconseja siempre utilizar conexiones asíncronas.

Propiedades

Las propiedades del objeto XMLHttpRequest son las siguientes:

  • onreadystatechange: Guarda el nombre de la función Javascript que manejará los cambios de estado en la petición.
  • readyState: Entero que codifica el estado actual de la petición
    • 0 = No Inicializado
    • 1 = Cargando
    • 2 = Cargado
    • 3 = Interactuando
    • 4 = Completado
  • responseText: Versión en forma de String de los datos devueltos por el servidor.
  • responseXML: Objeto DOM compatible de la respuesta del servidor.
  • status: Código de estado devuelto por el servidor, como 404 para No encontrado o 200 para Ok.
  • statusText: Mensaje que acompaña al código de estado.

De estas propiedades, las más importantes on onreadystatechange, readyState, y la respuesta responseText / responseXML.

La primera, onreadystatechange, sirve para asociar el método Javascript que hayamos escrito para gestionar los cambios de estado de la petición. Es decir, como es una comunicación asíncrona, se necesita tener un método implmentado por nosotros que gestione los diferentes eventos, como por ejemplo, la llegada de la respuesta. Esta es la propiedad que sirve para decirle a XMLHttpRequest el nombre de ese método.

La segunda, readyState, es un número que informa del estado de la petición. El estado más interesante es el número 4, que recoge el momento en el que llega la respuesta del servidor para poder procesarla.

La respuesta viene en dos versiones diferentes: Una en un texto normal, almacenada en la propiedad responseText; y otra en un objeto estándar DOM, almacenado en la propiedad responseXML. Lógicamente, el medio más poderoso de procesar las respuesta, es mediante el objeto DOM, ya que puede ser recorrido a través de los métodos estandarizados por la W3C DOM. Date cuenta que este DOM es un documento en XML, no en HTML.

Código general

Sabiendo todo esto, podemos crear una función genérica para realizar una petición:

var req;

function loadXMLDoc(url) {
    req = false;
    //  parte para cualquier navegador
    if(window.XMLHttpRequest) {
        try {
            req = new XMLHttpRequest();
        } catch(e) {
            req = false;
        }
    // parte para Internet Explorer / ActiveX
    } else if(window.ActiveXObject) {
        try {
         req = new ActiveXObject("Msxml2.XMLHTTP");
       } catch(e) {
            try {
               req = new ActiveXObject("Microsoft.XMLHTTP");
             } catch(e) {
                   req = false;
                    }
                }
        }
        if(req) {
            req.onreadystatechange = processReqChange;
            req.open("GET", url, true);
            req.send("");
    }
}

Y otra función para procesar las respuestas:

function processReqChange() {
    if (req.readyState == 4) {
        if (req.status == 200) {
            // ...Aquí irían la lógica necesaria
        } else {
            alert("Error recibiendo datos XML:\n" +
                req.statusText);
        }
    }
}

Seguridad

Por motivos de seguridad, no se puede acceder a los ficheros locales a través del protocolo file:// sin tener que lidiar con configuraciones. Debido a esto no se pueden hacer test de páginas locales directamente, y lo mejor es instalar un servidor HTTP como Apache y hacer conexiones http://localhost/.

También, el dominio de la dirección del servidor ha de ser el mismo que el de la página que contiene el script que realiza la petición.

Un ejemplo sencillo

Un ejemplo sencillo que he mirado para entender la idea básica de todo esto es el que proporciona Apple. Se trata de una página sencilla que utiliza los RSS de iTunes para cargar unas listas. Mira el código fuente, y verás que es fácil de entender.

Nada más. Espero que este artículo haya servido para que tanto tú como yo nos iniciemos en esto de AJAX.

Artículos (en inglés) que he leído para entender esto: