Cuando un sitio «vivo» requiere código vivo
\nImagina: estás escribiendo un mensajero en TypeScript. El usuario envía un mensaje — y el interlocutor debe verlo al instante, sin recargar la página. O un panel de bolsa, donde el precio de las acciones cambia cada segundo. O simplemente un feed de notificaciones que se actualiza solo. ¿Cómo implementarlo? Dos candidatos principales — long polling y WebSocket. Pero, ¿cuál elegir para no arruinar el rendimiento ni romper la UX?
\nEn este artículo, con ejemplos reales en TypeScript, analizaremos cómo funciona cada tecnología, dónde brillan y dónde fallan. Obtendrás no solo teoría, sino también fragmentos de código listos para Node.js y el navegador. ¡Allá vamos!
\n\n¿Qué es Long Polling en TypeScript y cómo funciona?
\nLong polling es una evolución de la solicitud HTTP normal. El cliente envía una solicitud al servidor, pero el servidor no responde de inmediato si no hay datos. Mantiene la conexión abierta hasta que ocurre un nuevo evento. Tan pronto como los datos están listos — el servidor envía la respuesta, el cliente la procesa e inmediatamente crea una nueva solicitud. El ciclo se repite.
\n¿Suena a parche? En parte sí. Pero funciona incluso a través de los proxies corporativos más estrictos que bloquean WebSocket.
\n\nImplementación de Long Polling en TypeScript (parte del servidor)
\nEscribamos un servidor simple con Express y TypeScript. Emulará una cola de mensajes.
\nimport express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\napp.use(express.json());\n\n// Almacenamiento de mensajes (simulación de cola)\nconst messages: string[] = [];\n\n// Endpoint para long polling\napp.get('/poll', (req: Request, res: Response) => {\n // Esperamos un nuevo mensaje hasta 30 segundos\n const checkForMessage = () => {\n if (messages.length > 0) {\n // Enviamos el primer mensaje y lo eliminamos de la cola\n const message = messages.shift();\n res.json({ data: message, timestamp: Date.now() });\n } else {\n // Si no hay mensajes — seguimos esperando\n setTimeout(checkForMessage, 1000); // verificamos cada segundo\n }\n };\n\n // Timeout por si no hay mensajes durante mucho tiempo\n const timeout = setTimeout(() => {\n res.json({ data: null, timeout: true });\n }, 30000);\n\n // Si el cliente se desconecta — limpiamos los temporizadores\n req.on('close', () => {\n clearTimeout(timeout);\n });\n\n checkForMessage();\n});\n\n// Endpoint para enviar mensaje\napp.post('/send', (req: Request, res: Response) => {\n const { message } = req.body;\n if (message) {\n messages.push(message);\n res.status(200).json({ status: 'ok' });\n } else {\n res.status(400).json({ error: 'message is required' });\n }\n});\n\napp.listen(3000, () => console.log('Long poll server on port 3000'));\n\nParte del cliente en TypeScript (navegador)
\nasync function startLongPolling() {\n try {\n const response = await fetch('http://localhost:3000/poll');\n const data = await response.json();\n\n if (data.data) {\n console.log('Nuevo mensaje:', data.data);\n // Actualizamos la UI\n updateUI(data.data);\n }\n\n // Iniciamos inmediatamente un nuevo poll\n startLongPolling();\n } catch (error) {\n console.error('Error en long polling:', error);\n // Esperamos 2 segundos y lo intentamos de nuevo\n setTimeout(startLongPolling, 2000);\n }\n}\n\nfunction updateUI(message: string) {\n // Tu código para actualizar el DOM\n const container = document.getElementById('messages');\n if (container) {\n const item = document.createElement('li');\n item.textContent = message;\n container.appendChild(item);\n }\n}\n\n// Iniciamos al cargar la página\ndocument.addEventListener('DOMContentLoaded', startLongPolling);\nConclusión: long polling es simple de implementar y no requiere protocolos especiales. Pero cada solicitud implica cabeceras HTTP, cookies, gastos generales. Con 1000 clientes simultáneos