⏱️ Asincronía en JavaScript
Aprende qué es la programación asíncrona y por qué es fundamental para crear aplicaciones web modernas. Entiende cómo JavaScript maneja tareas que toman tiempo.
1. Código síncrono (normal)
El código síncrono se ejecuta línea por línea, en orden. Cada línea espera a que la anterior termine antes de ejecutarse.
1console.log('1. Inicio');2console.log('2. Procesando...');3console.log('3. Fin');4 5// Salida:6// 1. Inicio7// 2. Procesando...8// 3. Fin✅ Ventaja:
Es fácil de entender: el código se ejecuta de arriba hacia abajo, en el orden que lo escribiste.
❌ Problema:
Si una operación tarda mucho (como cargar datos de un servidor), todo se detiene hasta que termine.
1console.log('Inicio');2 3// Imagina que esto tarda 5 segundos4const datos = cargarDatosDelServidor();5 6console.log('Fin'); // Espera 5 segundos antes de mostrarse7 8// ⏱️ La página queda "congelada" 5 segundos2. Código asíncrono (no bloqueante)
El código asíncrono permite que el programa continúe ejecutándose mientras espera que termine una tarea lenta.
Es como pedirle a alguien que haga café mientras tú sigues trabajando. No te quedas parado esperando, continúas con otras cosas.
Visualización interactiva:
Observa cómo se ejecuta el código síncrono vs asíncrono. Las cajas resaltadas muestran qué línea se está ejecutando:
Código Síncrono
Paso 1: EmpezarPaso 2: Tarea que tarda 5 segPaso 3: TerminarCódigo Asíncrono
Paso 1: EmpezarPaso 2: Programar tarea (5 seg)Paso 3: Terminar (no espera)Paso 2 completado (después)💡 Nota: En el código síncrono, todo se detiene en la tarea lenta. En el asíncrono, el programa continúa y ejecuta el callback cuando la tarea termina.
3. setTimeout - Tu primera función asíncrona
setTimeout() ejecuta código después de un tiempo, sin bloquear el resto del programa.
Sintaxis:
1setTimeout(function() {2 // Código a ejecutar3}, milisegundos);Ejemplo básico:
1console.log('1. Inicio');2 3setTimeout(function() {4 console.log('2. Esto se ejecuta después de 2 segundos');5}, 2000);6 7console.log('3. Fin');8 9// Salida:10// 1. Inicio11// 3. Fin12// (espera 2 segundos)13// 2. Esto se ejecuta después de 2 segundos⚠️ ¡Importante!
Observa que "3. Fin" se muestra ANTES que el mensaje del setTimeout, aunque está escrito después. Esto es porque setTimeout es asíncrono.
Con arrow function:
1console.log('Preparando café...');2 3setTimeout(() => {4 console.log('☕ ¡El café está listo!');5}, 3000);6 7console.log('Mientras tanto, sigo trabajando...');8 9// Salida:10// Preparando café...11// Mientras tanto, sigo trabajando...12// (espera 3 segundos)13// ☕ ¡El café está listo!Visualización de setTimeout:
Observa cómo setTimeout espera el tiempo especificado antes de ejecutar el callback:
Preparar café de forma asíncrona
Mientras el agua se calienta (3 segundos), podemos hacer otras cosas
4. Callbacks - Funciones que se ejecutan después
Un callback es una función que pasas como parámetro a otra función, para que se ejecute cuando termine una tarea.
Ejemplo simple:
1function hacerAlgo(callback) {2 console.log('Haciendo algo...');3 callback();4}5 6// Pasar una función como callback7hacerAlgo(function() {8 console.log('¡Terminé!');9});10 11// Salida:12// Haciendo algo...13// ¡Terminé!Ejemplo con setTimeout:
1function descargarDatos(callback) {2 console.log('📥 Descargando datos...');3 4 setTimeout(() => {5 const datos = { nombre: 'Juan', edad: 25 };6 callback(datos);7 }, 2000);8}9 10// Llamar con un callback11descargarDatos(function(datos) {12 console.log('✅ Datos recibidos:', datos);13});14 15console.log('Mientras tanto hago otras cosas...');16 17// Salida:18// 📥 Descargando datos...19// Mientras tanto hago otras cosas...20// (espera 2 segundos)21// ✅ Datos recibidos: { nombre: 'Juan', edad: 25 }💡 ¿Por qué usar callbacks?
- • Para ejecutar código cuando una tarea termine
- • Para manejar datos que llegan de forma asíncrona
- • Para responder a eventos (clicks, datos de servidor, etc.)
5. El problema: Callback Hell
Cuando necesitas hacer varias tareas asíncronas una después de otra, los callbacks se anidan y el código se vuelve difícil de leer.
1// ❌ Callback Hell (pirámide del infierno)2obtenerUsuario(function(usuario) {3 obtenerPedidos(usuario.id, function(pedidos) {4 obtenerDetalles(pedidos[0].id, function(detalles) {5 obtenerProductos(detalles.productos, function(productos) {6 console.log('Productos:', productos);7 // Difícil de leer y mantener8 });9 });10 });11});Problemas del Callback Hell:
- • Código difícil de leer (forma de pirámide)
- • Difícil de mantener y debuggear
- • Difícil manejar errores
✅ Solución:
En las próximas lecciones veremos Promises y async/await, que resuelven este problema de forma elegante.
6. ¿Cómo funciona? El Event Loop
JavaScript es single-threaded (un solo hilo), pero puede hacer múltiples cosas gracias al Event Loop.
Funcionamiento simplificado:
- 1. JavaScript ejecuta el código línea por línea
- 2. Cuando encuentra una tarea asíncrona (setTimeout, fetch, etc.), la envía al navegador
- 3. JavaScript continúa ejecutando el resto del código
- 4. Cuando la tarea asíncrona termina, su callback se añade a la cola
- 5. Cuando JavaScript termina todo el código síncrono, ejecuta los callbacks de la cola
1console.log('1. Inicio'); // Síncrono2 3setTimeout(() => {4 console.log('2. Callback asíncrono');5}, 0); // Aunque sea 0 ms, va a la cola6 7console.log('3. Fin'); // Síncrono8 9// Salida:10// 1. Inicio11// 3. Fin12// 2. Callback asíncrono13 14// Aunque setTimeout tenga 0ms, se ejecuta DESPUÉS15// porque primero termina todo el código síncronoVisualización del Event Loop:
Observa cómo el Event Loop maneja las tareas asíncronas a través del Call Stack, Web APIs y Callback Queue:
Event Loop en Acción
Call Stack
console.log('1')Web APIs
Callback Queue
1Ejecutando código síncrono: console.log('Inicio')
Ejercicio práctico
Simular carga de datos
Crea una función que simule cargar datos de un usuario con un setTimeout.
Requisitos:
- Crea una función llamada
cargarUsuario(callback) - Usa setTimeout para simular 2 segundos de carga
- Devuelve un objeto usuario con nombre y email usando el callback
- Muestra un mensaje mientras carga
Ver solución
1function cargarUsuario(callback) {2 console.log(' Cargando usuario...');3 4 setTimeout(() => {5 const usuario = {6 nombre: 'María López',7 email: 'maria@example.com'8 };9 10 callback(usuario);11 }, 2000);12}13 14// Usar la función15console.log('Inicio');16 17cargarUsuario(function(usuario) {18 console.log(' Usuario cargado:', usuario.nombre);19 console.log(' Email:', usuario.email);20});21 22console.log('Haciendo otras cosas mientras carga...');23 24// Salida:25// Inicio26// Cargando usuario...27// Haciendo otras cosas mientras carga...28// (espera 2 segundos)29// Usuario cargado: María López30// Email: maria@example.com📚 Resumen
Síncrono
Línea por línea, bloqueante
Simple pero lento para tareas largas
Asíncrono
No bloqueante, continúa ejecutando
Perfecto para tareas que toman tiempo
setTimeout
Ejecuta código después de X tiempo
setTimeout(fn, ms) Callbacks
Funciones que se ejecutan al terminar
Útiles pero pueden crear "callback hell"
Próxima lección: Veremos XMLHttpRequest (la forma vieja de hacer peticiones) para entender por qué Fetch es tan importante.