¿Cómo realizar una llamada AJAX sin bibliotecas?

publicado por: Anonymous

Con jQuery y otras bibliotecas JavaScript se pueden realizar llamadas AJAX de una manera sencilla utilizandoa algo como esto:

$.ajax({
   url: "miURl",
   method: "GET",
   data: "var1=valor1&var2=valor2",
   success: function(d) {
      // código aquí
   }
});

El problema es que en algunos proyectos me he encontrado con que añadía bibliotecas JavaScript exclusivamente para usar la función AJAX y para llamadas bastante básicas (principalmente GETs en los que no me importaba el error, sólo el resultado, si alguno)… y no tiene mucho sentido agregar un fichero de 85-300KB sólo para eso.

¿Cómo sería una función básica en JavaScript que tomase como parámetro una URL, una función que hará de success (no me importa el error) y opcionalmente el método (GET o POST), una lista de variables, y que funcionase de manera “similar” a como lo hace jQuery.ajax?

La respuesta debe ser independiente del servidor en el que se ejecute y si eso no es posible entonces debe funcionar para Apache.

solución

La respuesta debe ser independiente del servidor en el que se ejecute
y si eso no es posible entonces debe funcionar para Apache.

Uses la librería que uses, todo se transforma al mismo código (o parecido, pero usando los mismos estándares) y el servidor interpretará la misma petición.

Fuente: ¿Cómo funciona AJAX?.

De la parte naranja te encargas tú, el resto está predefinido en los servidores.


Voy a dividir mi respuesta en 2 líneas de tiempo 😉

Vieja escuela

Esta forma es la clásica y prácticamente multi-navegador, además de ser la estándar por muchos años. La clase que nos provee esto es la interface XMLHttpRequest.

Basta con crear un objeto XMLHttpRequest:

const xhr = new XMLHttpRequest();

Después, debemos especificar por medio del método open los siguientes parámetros:

  • Método de la petición
  • URL del recurso
  • Bandera para indicar si debe ser asíncrona (por defecto true)

Siguiendo con el ejemplo, podemos hacer lo siguiente:

xhr.open('GET', '//api.awesomemag.com/magazines');

Con esto ya establecemos los parámetro a la petición. Nos resta asociar una función para las fases de la petición del ciclo de vida de la petición.

xhr.onload = function() {
  if(xhr.readyState === 4) {
    // respuesta lista para procesar
  }
}

Una petición AJAX tiene un ciclo de vida durante su carga

Éstos son:

  • 0: Petición aún no inicializada
  • 1: Conexión establecida con el servidor
  • 2: Petición enviada
  • 3: Proceso de la petición
  • 4: Respuesta lista

Es por ésta razón que debemos actuar en la fase 4, cuando la respuesta esté lista para nosotros (salvo casos extraordinarios, como siempre, puede actuarse en otra(s) fase(s)):

if(xhr.readyState === 4) {
  // respuesta lista para procesar
}

Finalmente, enviamos la petición:

xhr.send();

Anexo: Envío de datos por POST

No es novedad que en una petición GET, no podemos enviar datos en el cuerpo de la petición; lo que hacen librerías como jQuery es leer el objetos que le pasamos a data y agruparlos por ?clave=valor para finalmente anexarlos a la URL.

Por el método POST sí se puede enviar datos, para lo cual disponemos de algunas opciones que menciono a continuación.

FormData

FormData es una interface que nos permite simular un submit de formulario enviando los datos que les añadamos como clave/valor, de hecho, ésta interface usa el mime multipart/form-data.

Veamos un ejemplo:

const data = new FormData();
data.append("title", "Be careful! NSA spy through smartphones backdoors!");
data.append("date", new Date().getTime());
xhr.send(data);

Forma manual

Esta forma es igual que con FormData, la diferencia es que acá lo haces de forma manual como si se tratase de parámetros get:

xhr.send('title=Be careful! NSA spy through smartphones backdoors!&date=' + new Date().getTime());

JSON

Para enviar objetos a través de XMLHttpRequest basta con hacer uso de JSON.stringify para serializar ese objeto:

xhr.send(JSON.stringify({
    title: 'Be careful! NSA spy through smartphones backdoors!',
    date: new Date().getTime()
}));

Nueva escuela

Recientemente ha sido liberada una nueva API basada en Promesas, llamada Fetch. De alguna manera, hace el código más limpio.

GET

Para realizar una petición GET, basta con pasar la URL del recurso y hacer uso de then y catch para el éxito y error respectivamente.

fetch('//api.awesomemag.com/magazines')
  .then(res => res.json())
  .then(magazines => console.log(magazines))
  .catch(err => console.log('Algo salió mal'));

Alternativamente, si esperamos recibir un JSON debemos incluir el header correspondiente:

fetch('//api.awesomemag.com/magazines', {
    headers: {
      accept: 'application/json'
    }
  })
  .then(res => res.json())
  .then(magazines => console.log(magazines))
  .catch(err => console.log('Algo salió mal'));

Pero hay otra razón por la cual ésta alternativa será muy utilizada y tiene que ver con una próxima característica de EcmaScript, se trata de Async/Await.

¿Cuál es la asociación entre Fetch y Async/Await?

Es muy simple. Async/Await hará posible esperar a que termine un procedimiento asíncrono, dándonos en ocasiones donde necesitemos éste comportamiento, una clara ventaja y naturalidad al programador backend generalmente procedural. Lo podemos entender mejor con un ejemplo:

function async getMagazines() {
  return fetch('//api.awesomemag.com/magazines');
}

// flujo natural
const magazines = await (getMagazines()).json();
// no necesitamos de promesas ni callbacks!

Algunas personas están en contra de esta nueva característica, argumentando que matan la naturaleza asíncrona de JavaScript.


Conclusiones

Propuestas en Stage 3+ prácticamente están aseguradas; en Stage 2 tienen una alta probabilidad de ser incluídas.

Actualmente disponemos de transpiladores que nos permiten usar EcmaScript 6,7 y 8 así como futuras inclusiones en el lenguaje sin perder compatibilidad entre navegadores. Una de las más famosas es Babel que transpila código moderno a EcmaScript 5 (JavaScript del 2009).

Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *