Apuntes javascript

JavaScript lo resuelve todo... eventualmente.

Curso de JavaScript para Principiantes - Lección 11: Introducción a la Programación Asíncrona

¡Bienvenido a la undécima lección! Hasta ahora, has aprendido a manipular el DOM y responder a eventos, haciendo tus páginas web interactivas. Pero, ¿qué pasa cuando necesitas cargar datos de un servidor, como una lista de productos o el perfil de un usuario? Estas operaciones toman tiempo, y JavaScript usa la programación asíncrona para manejarlas sin congelar la página. Si en PHP haces consultas a una base de datos con mysqli o PDO y esperas los resultados, en JavaScript la programación asíncrona es como esa espera, pero en el navegador y con un enfoque más dinámico.


¿Qué es la programación asíncrona?

En JavaScript, el código normalmente se ejecuta de forma síncrona, línea por línea. Pero algunas operaciones, como pedir datos a un servidor o esperar un temporizador, son asíncronas porque no se completan de inmediato. La programación asíncrona permite que JavaScript continúe ejecutando otro código mientras espera que esas operaciones terminen.

Ejemplo mental: Imagina que estás cocinando. Mientras esperas que el agua hierva (una tarea asíncrona), puedes picar verduras en lugar de quedarte parado. JavaScript hace lo mismo: sigue trabajando en otras tareas mientras espera una respuesta.

Conexión con PHP: En PHP, una consulta a una base de datos (SELECT * FROM usuarios) detiene el script hasta que recibe los datos. En JavaScript, usas herramientas como promesas o async/await para evitar que la página se "congele" mientras esperas datos de una API.


1. Entendiendo las Promesas

Una promesa es un objeto que representa una operación asíncrona que eventualmente se completará (o fallará). Una promesa puede estar en uno de tres estados:

  • Pendiente: La operación aún no ha terminado.
  • Cumplida: La operación se completó con éxito y devolvió un valor.
  • Rechazada: La operación falló y devolvió un error.

Sintaxis básica:

let promesa = new Promise((resolve, Hawkins) => {
  // Simula una operación asíncrona
  setTimeout(() => {
    if (Math.random() > 0.5) {
      resolve("¡Éxito!");
    } else {
      reject("Error: Algo salió mal");
    }
  }, 1000); // Espera 1 segundo
});

Usando una promesa:

promesa
  .then(resultado => {
    console.log(resultado); // Imprime: ¡Éxito!
  })
  .catch(error => {
    console.log(error); // Imprime: Error: Algo salió mal
  });
  • .then(): Ejecuta una función si la promesa se cumple.
  • .catch(): Ejecuta una función si la promesa falla.

2. Ejemplo Práctico: Simulando una Carga de Datos

Vamos a simular una operación asíncrona, como cargar datos de un servidor.

Ejemplo:

function cargarDatos() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      let exito = Math.random() > 0.3; // 70% de probabilidad de éxito
      if (exito) {
        resolve(["Manzana", "Banana", "Naranja"]);
      } else {
        reject("Error al cargar los datos");
      }
    }, 2000); // Espera 2 segundos
  });
}

cargarDatos()
  .then(datos => {
    console.log("Datos cargados:", datos);
  })
  .catch(error => {
    console.log(error);
  });

Cómo funciona:

  • La función cargarDatos devuelve una promesa.
  • Después de 2 segundos, la promesa se resuelve con un arreglo de frutas o se rechaza con un error.
  • .then() maneja los datos exitosos, y .catch() maneja los errores.

3. Usando async/await

La sintaxis async/await es una forma más limpia y legible de trabajar con promesas, haciendo que el código asíncrono parezca síncrono.

Sintaxis:

  • Declara una función como async.
  • Usa await dentro de la función para esperar el resultado de una promesa.

Ejemplo con async/await:

async function obtenerDatos() {
  try {
    let datos = await cargarDatos();
    console.log("Datos cargados:", datos);
  } catch (error) {
    console.log(error);
  }
}

obtenerDatos();
  • async: Indica que la función devuelve una promesa.
  • await: Pausa la ejecución hasta que la promesa se resuelva.
  • try/catch: Maneja errores, similar a .catch().

Conexión con PHP: Esto es como usar try/catch en PHP para manejar excepciones en una consulta a una base de datos, pero aplicado a operaciones asíncronas en el navegador.


4. Ejemplo Realista: Cargar Datos de una API

Vamos a usar la función fetch para cargar datos de una API pública, algo similar a hacer una consulta HTTP en PHP con curl.

HTML:

<!DOCTYPE html>
<html>
<head>
  <title>API de Usuarios</title>
</head>
<body>
  <h1>Usuarios</h1>
  <ul id="lista-usuarios"></ul>
  <button id="cargar">Cargar Usuarios</button>
  <script src="script.js"></script>
</body>
</html>

JavaScript (script.js):

let boton = document.getElementById("cargar");
let lista = document.getElementById("lista-usuarios");

async function cargarUsuarios() {
  try {
    let respuesta = await fetch("https://jsonplaceholder.typicode.com/users");
    let usuarios = await respuesta.json();
    lista.innerHTML = ""; // Limpia la lista
    usuarios.forEach(usuario => {
      let li = document.createElement("li");
      li.textContent = usuario.name;
      lista.appendChild(li);
    });
  } catch (error) {
    lista.innerHTML = "<li>Error al cargar usuarios</li>";
  }
}

boton.addEventListener("click", cargarUsuarios);

Cómo funciona:

  • fetch: Hace una solicitud HTTP a una API (similar a curl en PHP).
  • await fetch(...): Espera la respuesta de la API.
  • await respuesta.json(): Convierte la respuesta a un objeto JavaScript.
  • Los nombres de los usuarios se añaden a una lista en el DOM.
  • Si hay un error (como fallo de red), se muestra un mensaje de error.

Conexión con PHP: Esto es como usar file_get_contents o curl en PHP para obtener datos de una API, pero en JavaScript se hace en el navegador y se actualiza la página dinámicamente.


5. Buenas Prácticas

  1. Maneja errores siempre: Usa .catch() o try/catch para evitar que los errores rompan tu aplicación.
  2. Indica carga al usuario: Muestra un mensaje como "Cargando..." mientras esperas datos (puedes modificar el DOM).
  3. Evita promesas anidadas: Usa async/await para mantener el código legible.
  4. Valida datos de la API: Verifica que los datos recibidos sean válidos antes de usarlos.
  5. Prueba en un entorno real: Usa JSFiddle o un archivo HTML local para probar fetch con APIs públicas.

Ejercicios Prácticos

  1. Temporizador simple:

    • Crea una promesa que espere 3 segundos y resuelva con el mensaje "¡Tiempo cumplido!".
    • Usa .then() para mostrar el mensaje en la consola.
  2. Carga de datos simulada:

    • Crea una función que devuelva una promesa que, tras 2 segundos, resuelva con un arreglo de 3 nombres o falle con un error.
    • Usa async/await para manejar la promesa y mostrar los nombres en la consola.
  3. Cargar fotos de una API:

    • Crea un HTML con un <button> y un <div> vacío.
    • Al hacer clic en el botón, usa fetch con la API https://jsonplaceholder.typicode.com/photos para cargar los primeros 5 títulos de fotos y mostrarlos en el <div> como una lista (<ul>).
  4. Formulario con validación asíncrona:

    • Crea un HTML con un <input> para un nombre de usuario y un <button>.
    • Al hacer clic, simula una validación asíncrona (con una promesa que espere 1 segundo) que resuelva con "Usuario válido" si el nombre tiene más de 3 caracteres, o falle con "Nombre demasiado corto".
    • Muestra el resultado en un <p>.

Instrucción: Prueba estos ejercicios en JSFiddle o en un archivo HTML local con un <script>. Por ejemplo:

async function ejemplo() {
  let datos = await new Promise(resolve => setTimeout(() => resolve("¡Hecho!"), 1000));
  console.log(datos);
}
ejemplo();

Para la Próxima Lección

En la Lección 12, trabajaremos en un proyecto final: una aplicación simple, como una lista de tareas interactiva, que combine todo lo aprendido (variables, funciones, DOM, eventos, y asincronía). ¡Sigue practicando la programación asíncrona con los ejercicios de hoy para estar listo!

TOP