Cargas asíncronas de imágenes con jQuery en una web

- Andrés Cruz

In english

Cargas asíncronas de imágenes con jQuery en una web

AJAX por sus siglas en inglés de Asynchronous JavaScript And XML no es más que una tecnología que permite crear aplicaciones que mantienen una comunicación asíncrona con el servidor; en otras palabras podemos ejecutar funciones en paralelo con JavaScript mediante AJAXs con jQuery; la cual resulta ser una manera simple pero a su vez potente debido a la gran cantidad de posibilidades que ofrece y lo sencillo que resulta integrarlo con otras secciones de código (ya que a la final es JavaScript).

Uno de los grandes problemas que tiene el enfoque actual al momento de crear páginas webs, es que cada vez que agregamos dependencias mediante JavaScript o CSS e inclusive otros recursos como imágenes y vídeos, todas estas cosas al momento de ser consultada mediante una página web, el navegador va procesando poco a poco el contenido de la web desde el inicio hasta el final, cuando llega a la carga de un archivo CSS o JavaScript el navegador detiene la carga del HTML hasta que termine de cargar el recurso CSS o JavaScript en cuestión para luego seguir con el resto de la carga; seguramente en más de una ocasión al momento de incluir jQuery a tu sitio web e intentas emplear alguna funcionalidad de este framework JavaScript el navegador en su consola le da un error de algo como:

Uncaught TypeError: Cannot read property 'XXX' of undefined at <anonymous> </anonymous>

Y se debe a lo anterior explicado, si colocas algún código que dependa de una librería externa, esto no funcionará (y dará error) hasta que se cargue el recurso correspondiente.

El problema de la carga asíncrona en JavaScript

El problema principal de todo esto es que el navegador seguirá descargando contenido que forma parte de tu web y mediante este tiempo el acceso a tu web por parte del usuario sería nulo o limitado en el mejor de los casos y la web va cargando en trozos, y todo esto es tiempo que es directamente proporcional al tamaño y cantidad de recursos que estés cargando y todo esto afecta la experiencia final de tu sitio con el internauta y también el SEO, ya que los sitios lentos no los quiere nadie...

¿Qué nos ofrece AJAX?

Con lo expuesto anteriormente, entra en juego el Ajax o cargas asíncronas mediante JavaScript o nuestro caso de interés para esta entrada, jQuery que ofrece una manera más sencilla de cargas asíncronas que JavaScript puro.

Antes de entrar en el tema, recordemos que hace mucho tiempo la gente de Microsoft inventó una tecnología que luego se conocería como AJAX la cual era bastante primitiva y a la final solo permitía el uso de un thread o hilo en nuestra app (el hilo principal de la UI), realizaba la petición y bloqueaba el resto de la app hasta que terminara su ejecución cosa que ha evolucionado bastante hasta la fecha.

Ya volviendo a nuestro caso de interés, que es desarrollar aplicaciones que se ejecuten en paralelo; AJAX podemos hacer multitud de cosas para crear páginas interactivas sin la necesidad de refrescar todos los elementos de la página:

  • Podemos obtener datos en formato JSON o XML aunque este primero ha venido ganando relevancia con respecto a este último.
  • Podemos obtener una página completa (HTML, CSS, JavaScript) y manipularla a nuestro antojo desde JavaScript.
  • Podemos recibir información de manera asíncrona o síncrona según nuestras necesidades.

¿Pero... para que podemos usar AJAX?

  • Imaginense que deseas armar dos lista, una de empresas, y otras de proveedores en donde un proveedor pertenece a una empresa; sin adentrarnos demasiado en cómo sería el modelo de datos; el usuario debe de seleccionar una empresa para poder cargar un listado de proveedores que pertenecen a la empresa, esta carga puede hacerse mediante AJAX de manera asíncrona sin volver a cargar todo el documento; solo obtenemos la lista de proveedores y la llenamos dentro de la lista.
  • Imaginense que desea mostrar un overlay de distintas páginas desde la página principal según alguna opción seleccionada por el usuario; esta carga de páginas web o secciones se puede hacer de una manera muy simple con AJAX.

Con AJAX ninguna de las acciones anteriores requiere de una carga completa de la página (como lo tendría que hacer si no utilizaras AJAX), simplemente refrescar secciones del documento; inclusive podemos cargar recursos menos necesarios de manera asíncrona como imágenes:

Parámetros de jQuery.ajax()

jQuery.ajax() maneja una gran cantidad de parámetros que permiten configurar el AJAX de muchas maneras acorde a nuestras necesidades; pero entre los que considero más importantes podemos mencionar los siguientes:

  • URL del recurso al que se desea enviar la petición.
  • async (por defecto: true): Por defecto todas las peticiones son configuradas para que sean asíncronas; lo que significa que el resto del JavaScript sigue ejecutándose sin importar si termino de procesar la petición.
  • contentType: Indica explícitamente el tipo de datos a recibir desde el servidor.
  • error: Función que es invocada al ocurrir un error con la petición, incluidos los errores y/o estatus del servidor: 500, 404, 400 etc.
  • success: Función que es invocada cuando hubo éxito en el procesamiento de la petición.
  • type: GET o POST según sea el caso.

Ejemplos con AJAX y jQuery

En esta sección veremos un conjunto de ejemplos para demostrar algunas de las funcionalidades del AJAX y ejemplificando su uso en el camino; a lo largo de los ejemplos referenciamos algunos archivos a través de su URL:

  • El archivo pagina.html contiene: <html> <head> <title>Mi página</title> </head> <body> <h3>Mi página</h3> </body> </html>
  • El archivo test.php redirecciona a página.html: <?php readfile('pagina.html');
  • El archivo test2.php devuelve un JSON:
<?php
if(isset($_GET['id']))
 echo '{
    "aaData": [
        {
            "id": "132",
            "nombre_autor": "Jean",
            "apellido_autor": "Arp",
            "nombre_tipo": "Escultura",
            "nombre_zona": "Plaza Cubierta del Rectorado"
        },
        {
            "id": "133",
            "nombre_autor": "Jean",
            "apellido_autor": "Arp",
            "nombre_tipo": "Elementos plásticos",
            "nombre_zona": "Edif. de la Facultad de Humanidades y Educación"
        }
    ]
}';

Ejemplo de un jQuery.ajax() sencillo

El AJAX más sencillo que considero que podemos crear con jQuery debería ser algo muy similar al siguiente script:

var url="test.php";

$.ajax({
type : "GET",
url : url,
success : function(data) {
console.log("data",data);
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});

O inclusive podemos obtener la página directamente:

var url="pagina.html";

$.ajax({
type : "GET",
url : url,
success : function(data) {
console.log("data",data);
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});

En ambos casos, si miramos la consola de desarrolladores, veríamos algo como esto:

data <html>
<head>
<title>Mi página</title>
</head>
<body>
<h3>Mi página</h3>
</body>
</html>

Obtuvimos el contenido de la página HTML llamada página.html mediante AJAX.

¿Qué hicimos?

Solo enviamos una petición al recurso indicado en el parámetro url y retorna un contenido.

El recurso podría ser también un XML, JSON, un archivo, etc.

Ejemplo de jQuery.ajax() con pase de parámetros

Si nuestro recurso necesita pasarle uno o varios parámetros, es necesario emplear el parámetro data como veremos a continuación:

var url="test2.php";
$.ajax({
type : "GET",
data : {
	id : 5
},
url : url,
success : function(data) {
console.log("data",data);
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});

Si miramos la consola de desarrolladores, veríamos un String como esto:

data {
    "aaData": [
        {
            "id": "132",
            "nombre_autor": "Jean",
            "apellido_autor": "Arp",
            "nombre_tipo": "Escultura",
            "nombre_zona": "Plaza Cubierta del Rectorado"
        },
        {
            "id": "133",
            "nombre_autor": "Jean",
            "apellido_autor": "Arp",
            "nombre_tipo": "Elementos plásticos",
            "nombre_zona": "Edif. de la Facultad de Humanidades y Educación"
        }
    ]
}

Y tuviésemos que castear el mismo a un array para poder manipularlo con un método como:

$.parseJSON(data);

Si queremos traer un JSON mediante AJAX ya casteado como un array para poder manipularlo fácilmente:

$.getJSON(url, function( data ) {
  console.log("data",data);
});

La diferencia

Ahora devuelve la data como un array en vez de un string.

data 
Object {aaData: Array[2]}
aaData: Array[2]
0: Object
apellido_autor: "Arp"
id: "132"
nombre_autor: "Jean"
nombre_tipo: "Escultura"
nombre_zona: "Plaza Cubierta del Rectorado"
__proto__: Object
1: Object
apellido_autor: "Arp"
id: "133"
nombre_autor: "Jean"
nombre_tipo: "Elementos plásticos"
nombre_zona: "Edif. de la Facultad de Humanidades y Educación"

¿Cual es el objetivo de pasar data en el request?

Si estamos interesados en obtener un listado dado un o una serie identificadores, debemos emplear el parámetro data indicando el nombre del parámetro y el valor del mismo; si son varios hay que separarlos por comas (,) los parámetros:

data : {
	id : 5,
	nombre : 'juan'
},

¿Cómo enviar un formulario por AJAX?

Si queremos enviar un formulario por AJAX, podemos emplear el método serialize() provisto por jQuery que ya hemos hablado en otra ocasión: Así funciona serialize en jQuery.

$.ajax({
type : "GET",
data: $("form").serialize(),
url : url,
success : function(data) {
console.log("data",data);
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});

Métodos Ajax en jQuery

En caso de que no quieras emplear el método $.ajax puedes emplear otros métodos para ahorrarnos algunas líneas de JavaScript y que también nos permitirán crear código más conciso y descriptivo:

  • $.get Realiza una petición GET a una URL proporcionada.
  • $.post Realiza una petición POST a una URL proporcionada.
  • $.getJSON Realiza una petición GET a una URL proporcionada y espera que el dato devuelto sea un JSON; si la data devuelta no es un JSON, pues el script fallará.

En cuanto a los argumentos que debes establecer son los siguientes:

  • url La URL a la cual se va a realizar la petición; su valor es obligatorio ya que sin la URL no hay recurso que generar.
  • data La información que se enviará al servidor mediante GET o POST; su uso es opcional y puede ser tanto un objeto como una cadena de datos: foo=bar&baz=bim).
  • success callback Una función opcional pero prácticamente necesaria que se si y sólo si la consulta fue exitosa y desde aquí podemos acceder a los datos y realizar el manejo de los mismos.
  • error callback Esta función es opcional y se ejecuta en caso de que la petición o consulta no fue exitosa.
  • data type El tipo de dato que se espera recibir desde el servidor. Su valor es opcional.
// Consulta get con pase de parametros y data devuelta en texto plano
$.get('/user_data.php', { user_id : <?php echo $user_id >?}, function(data) {
    console.log(data);
});
 
// obtiene data en formato JSON sin parametros
$.getJSON('/pais_json.php', function(json) {
     console.log(json);
});

Sincrono VS Asincrono con AJAX

Un punto interesante de la tecnología AJAX es que es asíncrono; es decir, que el AJAX se ejecuta sin interrumpir el resto del código JavaScript; esto puede resultar en un inconveniente en algunas ocasiones dependiendo de las circunstancias o de lo que deseamos hacer:

$.ajax({
type : "GET",
url : url,
success : function(data) {
console.log("msj1","esto se ejecutará de último");
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});
console.log("msj2","esto se ejecutará antes del ajax");

Retorna los mensajes en el siguiente orden:

msj2 esto se ejecutará antes del ajax msj1 esto se ejecutará de último

Ya que el AJAX no "bloquea" al resto del JavaScript por defecto no detiene la ejecución del JavaScript restante.

Si queremos que por defecto se "bloquee" o detenga la ejecución del JavaScript, debemos usar el parámetro async (asíncrono) establecido en false.

$.ajax({
type : "GET",
async : false,
url : url,
success : function(data) {
console.log("msj1","esto se ejecutará primero");
},
error : function(objXMLHttpRequest) {
console.log("error",objXMLHttpRequest);
}
});
console.log("msj2","esto se ejecutará después del ajax");

msj1 esto se ejecutará primero msj2 esto se ejecutará después del ajax

Funciones y parámetros del método $.ajax

EL método $.ajax posee varias opciones de configuración que podemos emplear para adaptar el script a nuestras necesidades; puedes consultar la lista completa en jQuery Ajax; entre las principales tenemos:

  • async Establece si la petición será asíncrona o no; de manera predeterminada el valor es true; colocar el valor el false bloqueará la ejecución del código hasta que la petición finalice; es ideal colocarlo en false para cuando queremos que la data retornada la quieres establecer en una variable global o algo similar.
  • data Establece la data a enviar al servidor empleando las mismas consideraciones que explicamos anteriormente.
  • jsonp Este parámetro es muy útil y permite indicar si la data de vuelta será en formato JSON o no.
  • type Este parámetro permite establecer si la consulta o petición será mediante GET (por defecto) u otro como POST
  • url Con este parámetro establece la URL del recurso al cual se le va a realizar la petición.
  • complete Es una función que al igual que la de success es la función callback que se ejecuta cuando la petición terminó de manera satisfactoria.
  • error Esta función se ejecuta cuando ocurre un error en la petición.

Extra: Funciones de promesas: Async/Await al rescate

Hasta ahora hemos visto cómo realizar el callback "tradicional" en donde tenemos una función que se ejecuta en paralelo de manera asíncrona, trae data, y hacemos algo con esa data como llenar un listado, una tabla, etc; pero podemos llevar todo esto a otro nivel, dando un nivel de embebido mayor con nuestro código mediante las funciones de promesas.

Las funciones de promesa permite manejar el flujo y manejar errores.

Las promesas permiten además de mejorar el flujo en nuestra app "handlear" errores o manejarlos de una manera más sencilla mediante el ya más que conocido try y catch; para usar las funciones de promesas debemos agregar un par de palabras reservadas llamadas async y await:

function getDepartamentosJson(pais_id) {
    return $.getJSON("/clientes/j_departamento_by_pais_id/"+pais_id);
}

async function getDepartamentos() {
    try {
      var departamentos = await getDepartamentosJson(1);

//          departamentos = jQuery.parseJSON(departamentos);
      if(departamentos.length == 0) throw new Error('Sin data');

       // hacer otra cosa
       return departamentos;
    } catch(e) {
      console.log(e)
    }
}

Como vemos en el código anterior, nuestro código tiene una estructura de código síncrono pero en realidad es asíncrono, ya que cuando devuelva la data getDepartamentosJson() se ejecutará la función getDepartamentos() y todo esto gracias a la palabra reservada async que colocamos en la función y await que indica que la función getDepartamentos() seguirá ejecutándose una vez que termine de ejecutarse la función getDepartamentosJson().

Enlaces de Interés

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz En Udemy

Acepto recibir anuncios de interes sobre este Blog.