Solicitudes asíncronas (AJAX)
XHR API, Fetch API y promesas.
¿Qué es AJAX?
AJAX no es un lenguaje de programación.
AJAX = Asynchronous JavaScript and XML(JavaScript asíncrono y XML).
Es una técnica de desarrollo web para crear aplicaciones interactivas). Estas aplicaciones se ejecutan en el cliente, es decir, en el navegador de los usuarios mientras se mantiene la comunicación asíncrona con el servidor en segundo plano. De esta forma es posible realizar cambios sobre las páginas sin necesidad de recargarlas, mejorando la interactividad, velocidad y usabilidad en las aplicaciones.
En realidad AJAX es un nombre engañoso. Algunas aplicaciones podrían utilizar XML para transportar data, pero es igualmente común transportar la data en JSON, HTML o en texto plano. Ejemplo.
AJAX solo utiliza la combinación de:
- Un navegador que tenga incorporado el objeto
XMLHttpRequest
(Es un API en la forma de un objeto cuyos métodos transfieren data entre un navegador web y un servidor web.) - Javascript y el DOM HTML (para mostrar o utilizar esa data)
1- Un evento ocurre en un sitio web (La página es cargada, un botón es clickeado).
2- Se crea una instancia de XMLHttpRequest utilizando Javascript.
3- El objeto XMLHttpRequest envía un request al servidor web.
4- El servidor procesa el request.
5- El servidor envía de vuelta una respuesta a la página web.
6- La respuesta es leída utilizando Javascript.
7- Se realiza la acción correspondiente, por ejemplo, actualizar la página con información nueva.
Clásico método XMLHttpRequest:
// Creamos una instancia nueva de XMLHttpRequestvar xhttp = new XMLHttpRequest();// Definimos una función que manejará la solicitud HTTP a través del estado.xhttp.onreadystatechange = function() { // Si la solicitud ha sido procesada y la respuesta contiene un status 200, entonces utilizamos la data que nos devuelve el servidor web. if (this.readyState == 4 && this.status == 200) {
// Parseamos la respuesta a JSON let jsonResponse = JSON.parse(this.response) // Utilizamos el valor de la key "message", para modificar el contenido HTML del elemento seleccionado. document.getElementById("testing-div").innerHTML = jsonResponse.message }};// Abrimos un request, utilizando el método "GET" y la ruta a la cual será enviada.xhttp.open("GET", `get_welcome_data`, true);// Enviamos el requestxhttp.send();
Método con Fetch API
¿Qué es la Fetch API?
La Fetch API es una interfaz simple para obtener recursos. Fetch nos permite realizar solicitudes HTTP y manejar sus respuestas de una manera mas fácil que nuestro viejo amigo XMLHttpRequest(XHR).
Una de las principales diferencias es que Fetch API utiliza Promises, las cuales nos provee una manera para evitar el “callback hell” y todo el código pesado y repetitivo que se utilizaría en XHR. Ejemplo de “callback hell”:
La función fetch toma un argumento mandatorio, el cual es el path al recurso que quieres obtener y retorna una promesa que resuelve la respuesta de la solicitud.
¿Qué son Promises?
El objeto Promise representa la finalización (o falla) de una operación asíncrona y su valor resultante.
Las promesas nos brindan una alternativa más simple a la ejecución, composición y administración de tareas asíncronas comparado al tradicional uso de callbacks.
Una promesa puede tener uno de los siguientes estados:
- Pending(pendiente): estado inicial, no ha sido ni cumplida ni rechazada.
- Fulfilled(cumplida): significa que la operación se completó satisfactoriamente
- Rejected(rechazada): significa que la operación falló.
Cuando una promesa esta en “Pending” puede transformarse a cumplida o rechazada. Una vez cambie su estado a cumplida o rechazada, no puede cambiar a otro estado, ni su valor podrá cambiar.
Utilizando Fetch API y promesas
Realicemos un ejemplo donde utilicemos la Fetch API y Promises para renderizar una lista que contiene data desde el endpoint de un API pública.
Intentemos obtener data desde la API de reqres.in
//Definimos una promesaconst fetchPromise = fetch("https://reqres.in/api/users");console.log(fetchPromise);
Cuando hacemos una solicitud HTTP como una operación asíncrona, fetch no retornará data. Sin embargo, retornará una promesa como respuesta. Cuando vemos el log, muestra que la promesa esta en estado pendiente. Esto quiere decir que la respuesta llegará en algún punto, pero al momento de mostrar el mensaje, la respuesta no había sido resuelta.
Nuestra promesa puede ahora cambiar a finalizada si todo va bien o rechazada si ocurrió algún error.
Continuemos con nuestro ejemplo y aprendamos como extraer la data desde la respuesta de nuestra Promise. Para ello utilizaremos el método then para definir lo que se va a ejecutar una vez nuestra promesa haya sido cumplida.
const fetchPromise = fetch("https://reqres.in/api/users");
fetchPromise.then(response => {
console.log(response);
});
Mostramos la respuesta por la consola, para observar la data que recibimos desde el API. Dicha respuesta contiene alguna información, incluye headers, body, type e incluso el código de status.
Ahora que sabemos que la respuesta del API esta funcionando bien, vamos a trabajar realmente con el body de la respuesta. Para ello utilizamos el método json() en la respuesta para obtener el body de la respuesta en formato JSON.
El método json() en realidad retorna una Promise, por lo cual vamos a crear una cadena de Promises.
Vamos a pasar el valor obtenido desde nuestra primera Promise en nuestra cadena, para realizar algúnas operaciones. En este caso vamos a pasar el objeto responseInJson.
const fetchPromise = fetch("https://reqres.in/api/users");
fetchPromise.then(response => {
return response.json();
}).then(responseInJson => {
console.log(responseInJson);
});
Cuando observamos la consola tenemos un objeto JSON con esta estructura:
Luego encadenamos una ultima promesa para obtener a la key “data” de nuestra respuesta en JSON.
const fetchPromise = fetch("https://reqres.in/api/users");
fetchPromise.then(response => {
return response.json();
}).then(responseInJson => {
return responseInJson.data;
})
.then(data =>{
console.log(data);
});
Y el resultado es:
La data de los usuarios que nos provee el API.
Ahora podemos hacer lo que queramos con dicha data, guardarla en un array, hacer “append” de esa data en un div, entre otros.
¿Qué hacemos cuando ocurre un error?
Digamos que por ejemplo nos equivocamos en la url a la cual le haremos la solicitud HTTP:
const fetchPromise = fetch("https://reqres.in/equivocado");
fetchPromise.then(response => {
return response.json();
}).then(responseInJson => {
return responseInJson.data;
})
.then(data =>{
console.log(data);
});
Que mal! Nos retorna, error no capturado en la promesa:
Para evitar dicho comportamiento podemos utilizar el método .catch para capturar el error y realizar una acción controlada por nosotros.
const fetchPromise = fetch("https://reqres.in/equivocado");
fetchPromise.then(response => {
return response.json();
}).then(responseInJson => {
return responseInJson.data;
})
.then(data =>{
console.log(data);
})
.catch(error => {
console.log('Hubo un problema con la petición Fetch');
});
Eso es todo por ahora con respecto a Fetch API y promises, te invito a seguir investigando y practicando para aprender mas a fondo su uso. Si tienes alguna sugerencia, duda o solo quieres saludar, puedes hacerlo en la sección de comentarios debajo.