JavaScript

JavaScript

Tutorial JavaScript: WebSockets

WebSocket Handshake y transición HTTP a WebSocket: optimiza conexiones bidireccionales para apps en tiempo real con WSS.

Aprende JavaScript y certifícate

Establecimiento de conexión: Handshake inicial y transición del protocolo HTTP a WebSocket

Los WebSockets representan un avance significativo en la comunicación web, permitiendo una conexión bidireccional y persistente entre el navegador y el servidor. A diferencia del modelo tradicional de petición-respuesta de HTTP, WebSocket mantiene un canal de comunicación abierto, lo que resulta ideal para aplicaciones que requieren actualizaciones en tiempo real.

El proceso de handshake

El establecimiento de una conexión WebSocket comienza con un proceso llamado handshake (apretón de manos), que transforma una conexión HTTP normal en una conexión WebSocket persistente. Este proceso ocurre en varias etapas bien definidas:

  1. Solicitud inicial desde el cliente: El cliente inicia el proceso enviando una solicitud HTTP estándar, pero con cabeceras especiales que indican su intención de establecer una conexión WebSocket:
// Crear una nueva instancia de WebSocket
const socket = new WebSocket('ws://ejemplo.com/socket');

// La conexión se inicia automáticamente al crear la instancia
console.log('Iniciando handshake WebSocket...');

Cuando ejecutamos este código, el navegador envía una solicitud HTTP con las siguientes cabeceras especiales:

  • Upgrade: websocket - Indica que queremos cambiar el protocolo
  • Connection: Upgrade - Confirma la intención de actualizar la conexión
  • Sec-WebSocket-Key - Clave aleatoria generada por el cliente
  • Sec-WebSocket-Version - Versión del protocolo WebSocket (generalmente 13)

Respuesta del servidor y establecimiento de la conexión

El servidor debe responder correctamente para completar el handshake:

// Este código se ejecutaría en el servidor (Node.js con la biblioteca 'ws')
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

server.on('connection', socket => {
  console.log('Cliente conectado - Handshake completado');
  // La conexión ya está establecida
});

Para que el handshake sea exitoso, el servidor debe responder con:

  • Código de estado HTTP 101 Switching Protocols
  • Cabecera Upgrade: websocket
  • Cabecera Connection: Upgrade
  • Cabecera Sec-WebSocket-Accept con un valor calculado a partir del Sec-WebSocket-Key enviado por el cliente

Detección del estado de la conexión

Es fundamental monitorear el estado de la conexión mediante los eventos del WebSocket:

const socket = new WebSocket('ws://ejemplo.com/socket');

// Evento disparado cuando el handshake se completa exitosamente
socket.addEventListener('open', event => {
  console.log('Conexión establecida correctamente');
});

// Evento disparado si hay problemas durante el handshake
socket.addEventListener('error', event => {
  console.error('Error en la conexión WebSocket');
});

Protocolo WSS (WebSocket Secure)

Al igual que HTTPS es la versión segura de HTTP, WSS es la versión cifrada de WebSocket:

// Establecer una conexión WebSocket segura
const secureSocket = new WebSocket('wss://ejemplo.com/socket');

El protocolo wss:// utiliza TLS/SSL para cifrar la comunicación, proporcionando las mismas ventajas de seguridad que HTTPS. Es altamente recomendado para entornos de producción, especialmente cuando se transmiten datos sensibles.

Verificación del soporte del navegador

Antes de intentar establecer una conexión WebSocket, es buena práctica verificar si el navegador soporta esta tecnología:

if ('WebSocket' in window) {
  // El navegador soporta WebSockets
  const socket = new WebSocket('ws://ejemplo.com/socket');
} else {
  // Proporcionar una alternativa o notificar al usuario
  console.log('Tu navegador no soporta WebSockets');
}

Transición del protocolo

Una vez completado el handshake, la conexión deja de ser HTTP y se convierte completamente en WebSocket. Esto significa que:

  • La conexión permanece abierta indefinidamente hasta que alguna de las partes la cierre
  • La comunicación se vuelve bidireccional y cualquiera de las partes puede iniciar el envío de mensajes
  • El formato de los datos cambia del formato HTTP a tramas binarias WebSocket
  • La sobrecarga de comunicación se reduce significativamente al eliminar las cabeceras HTTP en cada intercambio

Esta transición de protocolo es lo que permite a WebSocket ofrecer comunicación en tiempo real con una latencia mucho menor que las soluciones basadas en HTTP tradicional como polling o long polling.

Intercambio de mensajes: Formatos de datos, serialización y manejo de eventos

Una vez establecida la conexión WebSocket, el intercambio de mensajes se convierte en el aspecto central de la comunicación. A diferencia del modelo HTTP tradicional, WebSocket permite enviar y recibir datos en cualquier momento sin necesidad de iniciar nuevas conexiones, lo que resulta ideal para aplicaciones en tiempo real.

Envío y recepción de mensajes básicos

El API de WebSocket proporciona métodos simples pero potentes para la comunicación bidireccional:

const socket = new WebSocket('ws://example.com/socket');

// Enviar un mensaje de texto simple
socket.addEventListener('open', () => {
  socket.send('Hola servidor');
});

// Recibir mensajes del servidor
socket.addEventListener('message', event => {
  console.log(`Mensaje recibido: ${event.data}`);
});

El método send() es la forma principal de transmitir datos al servidor, mientras que el evento message nos permite capturar la información entrante.

Formatos de datos soportados

WebSocket admite varios tipos de datos para el intercambio de mensajes:

  • Cadenas de texto: El formato más común y sencillo de utilizar.
  • ArrayBuffer: Para datos binarios como imágenes o archivos.
  • Blob: Para grandes objetos binarios.
  • TypedArray: Para datos numéricos estructurados.
// Enviar diferentes tipos de datos
socket.send('Mensaje de texto simple');

// Enviar datos binarios
const binaryData = new Uint8Array([1, 2, 3, 4]);
socket.send(binaryData.buffer);

// Enviar un blob (por ejemplo, una imagen)
fetch('/imagen.jpg')
  .then(response => response.blob())
  .then(blob => socket.send(blob));

Serialización JSON para objetos complejos

Para transmitir estructuras de datos complejas, la serialización JSON es la técnica más utilizada:

// Enviar un objeto JavaScript serializado
const userData = {
  id: 123,
  username: 'usuario1',
  isActive: true,
  preferences: {
    theme: 'dark',
    notifications: true
  }
};

socket.send(JSON.stringify(userData));

// En el receptor, parseamos el JSON
socket.addEventListener('message', event => {
  try {
    const data = JSON.parse(event.data);
    console.log(`Usuario: ${data.username}`);
  } catch (error) {
    console.error('Mensaje recibido no es JSON válido');
  }
});

Es importante implementar un manejo adecuado de errores al deserializar, ya que no todos los mensajes podrían ser JSON válido.

Protocolos de mensajería y formatos estructurados

Para aplicaciones más complejas, es recomendable definir un protocolo de mensajería que incluya metadatos como el tipo de mensaje:

// Enviar mensaje con formato estructurado
function sendMessage(type, payload) {
  const message = {
    type,
    payload,
    timestamp: Date.now()
  };
  socket.send(JSON.stringify(message));
}

// Ejemplos de uso
sendMessage('chat', { text: 'Hola a todos' });
sendMessage('userJoined', { userId: 42, username: 'alice' });

Este enfoque facilita el enrutamiento de mensajes en el receptor:

socket.addEventListener('message', event => {
  const message = JSON.parse(event.data);
  
  switch (message.type) {
    case 'chat':
      displayChatMessage(message.payload);
      break;
    case 'userJoined':
      notifyUserJoined(message.payload);
      break;
    default:
      console.warn(`Tipo de mensaje desconocido: ${message.type}`);
  }
});

Sistema de eventos para mensajes

Podemos implementar un sistema de eventos personalizado para manejar diferentes tipos de mensajes de forma más modular:

class WebSocketClient {
  constructor(url) {
    this.socket = new WebSocket(url);
    this.eventHandlers = {};
    
    this.socket.addEventListener('message', event => {
      const message = JSON.parse(event.data);
      this.trigger(message.type, message.payload);
    });
  }
  
  on(eventName, callback) {
    if (!this.eventHandlers[eventName]) {
      this.eventHandlers[eventName] = [];
    }
    this.eventHandlers[eventName].push(callback);
  }
  
  trigger(eventName, data) {
    const handlers = this.eventHandlers[eventName] || [];
    handlers.forEach(handler => handler(data));
  }
  
  send(type, data) {
    this.socket.send(JSON.stringify({ type, payload: data }));
  }
}

Este patrón permite un código más limpio y mantenible:

const client = new WebSocketClient('ws://example.com/socket');

// Registrar manejadores para diferentes tipos de mensajes
client.on('userList', users => {
  updateUserInterface(users);
});

client.on('newMessage', message => {
  addMessageToChat(message);
});

// Enviar mensajes
client.send('requestUserList', { roomId: 'general' });

Compresión de datos

Para optimizar el rendimiento en conexiones lentas o cuando se transmiten grandes volúmenes de datos, podemos implementar compresión:

// Función para comprimir datos antes de enviarlos
async function sendCompressed(socket, data) {
  // Convertir a JSON y luego a Uint8Array
  const jsonString = JSON.stringify(data);
  const textEncoder = new TextEncoder();
  const uint8Array = textEncoder.encode(jsonString);
  
  // Comprimir usando CompressionStream (API moderna)
  const compressedStream = new CompressionStream('gzip');
  const writer = compressedStream.writable.getWriter();
  writer.write(uint8Array);
  writer.close();
  
  // Leer el resultado comprimido
  const reader = compressedStream.readable.getReader();
  const chunks = [];
  
  while (true) {
    const { value, done } = await reader.read();
    if (done) break;
    chunks.push(value);
  }
  
  // Combinar chunks y enviar
  const compressedData = new Blob(chunks);
  socket.send(compressedData);
}

Validación de mensajes

La validación de datos es crucial para mantener la seguridad y estabilidad:

function validateMessage(message) {
  // Verificar estructura básica
  if (!message || typeof message !== 'object') {
    return false;
  }
  
  // Verificar campos requeridos
  if (!message.type || !message.payload) {
    return false;
  }
  
  // Validaciones específicas según el tipo
  switch (message.type) {
    case 'chat':
      return typeof message.payload.text === 'string' && 
             message.payload.text.length <= 500;
    case 'userAction':
      return ['join', 'leave', 'typing'].includes(message.payload.action);
    default:
      return false;
  }
}

// Uso en el receptor
socket.addEventListener('message', event => {
  try {
    const message = JSON.parse(event.data);
    if (validateMessage(message)) {
      processMessage(message);
    } else {
      console.warn('Mensaje recibido no válido');
    }
  } catch (error) {
    console.error('Error al procesar mensaje');
  }
});

Manejo de mensajes binarios

Para trabajar con datos binarios como imágenes o archivos:

socket.binaryType = 'arraybuffer'; // También puede ser 'blob'

socket.addEventListener('message', async event => {
  // Verificar si es un mensaje binario
  if (event.data instanceof ArrayBuffer) {
    // Procesar datos binarios
    const view = new Uint8Array(event.data);
    processImageData(view);
  } else {
    // Procesar mensaje de texto normal
    const textData = event.data;
    console.log(`Texto recibido: ${textData}`);
  }
});

La propiedad binaryType determina cómo se representarán los datos binarios recibidos, permitiéndonos elegir el formato más conveniente para nuestra aplicación.

Gestión del ciclo de vida: Reconexión automática, heartbeats y cierre controlado

La gestión del ciclo de vida de una conexión WebSocket es fundamental para crear aplicaciones robustas y resistentes a fallos. Una conexión WebSocket puede interrumpirse por diversos motivos: problemas de red, reinicio del servidor o tiempos de inactividad prolongados. Implementar estrategias adecuadas para manejar estas situaciones garantiza una experiencia de usuario fluida y consistente.

Monitorización del estado de la conexión

El primer paso para gestionar el ciclo de vida es monitorizar constantemente el estado de la conexión mediante los eventos nativos de WebSocket:

const socket = new WebSocket('wss://example.com/socket');

socket.addEventListener('open', () => {
  console.log('Conexión establecida');
  setConnectionStatus('connected');
});

socket.addEventListener('close', event => {
  console.log(`Conexión cerrada: código ${event.code}, razón: ${event.reason}`);
  setConnectionStatus('disconnected');
  
  // El código 1000 indica cierre normal
  if (event.code !== 1000) {
    handleReconnection();
  }
});

socket.addEventListener('error', error => {
  console.error('Error en la conexión WebSocket');
  setConnectionStatus('error');
});

Los códigos de cierre proporcionan información valiosa sobre el motivo de la desconexión:

  • 1000: Cierre normal
  • 1001: El endpoint se está yendo (por ejemplo, servidor reiniciándose)
  • 1002-1015: Varios errores de protocolo
  • 4000+: Códigos personalizados definidos por la aplicación

Implementación de reconexión automática

La reconexión automática es esencial para mantener la comunicación a pesar de interrupciones temporales:

class ReconnectingWebSocket {
  constructor(url, options = {}) {
    this.url = url;
    this.options = options;
    this.socket = null;
    this.isConnected = false;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = options.maxReconnectAttempts || 10;
    this.reconnectInterval = options.reconnectInterval || 1000;
    this.listeners = { message: [], open: [], close: [], error: [] };
    
    this.connect();
  }
  
  connect() {
    this.socket = new WebSocket(this.url);
    
    this.socket.addEventListener('open', event => {
      this.isConnected = true;
      this.reconnectAttempts = 0;
      this.triggerEvent('open', event);
    });
    
    this.socket.addEventListener('close', event => {
      this.isConnected = false;
      this.triggerEvent('close', event);
      
      if (event.code !== 1000 && this.reconnectAttempts < this.maxReconnectAttempts) {
        const delay = this.getReconnectDelay();
        setTimeout(() => this.reconnect(), delay);
      }
    });
    
    this.socket.addEventListener('message', event => {
      this.triggerEvent('message', event);
    });
    
    this.socket.addEventListener('error', event => {
      this.triggerEvent('error', event);
    });
  }
  
  reconnect() {
    this.reconnectAttempts++;
    console.log(`Intento de reconexión ${this.reconnectAttempts}...`);
    this.connect();
  }
  
  getReconnectDelay() {
    // Implementación de backoff exponencial
    return Math.min(30000, this.reconnectInterval * Math.pow(1.5, this.reconnectAttempts));
  }
  
  addEventListener(type, callback) {
    if (this.listeners[type]) {
      this.listeners[type].push(callback);
    }
  }
  
  triggerEvent(type, event) {
    (this.listeners[type] || []).forEach(callback => callback(event));
  }
  
  send(data) {
    if (this.isConnected) {
      this.socket.send(data);
      return true;
    }
    return false;
  }
  
  close(code = 1000, reason = '') {
    if (this.socket) {
      this.socket.close(code, reason);
    }
  }
}

Esta implementación incluye un backoff exponencial, una técnica que aumenta progresivamente el tiempo entre intentos de reconexión para evitar sobrecargar el servidor.

Heartbeats para mantener la conexión activa

Los heartbeats (latidos) son mensajes periódicos que verifican si la conexión sigue activa, especialmente útiles para evitar que intermediarios como proxies o firewalls cierren conexiones inactivas:

class HeartbeatWebSocket {
  constructor(url, options = {}) {
    this.url = url;
    this.socket = new WebSocket(url);
    this.heartbeatInterval = options.heartbeatInterval || 30000;
    this.heartbeatTimer = null;
    this.missedHeartbeats = 0;
    this.maxMissedHeartbeats = options.maxMissedHeartbeats || 3;
    
    this.setupEventListeners();
  }
  
  setupEventListeners() {
    this.socket.addEventListener('open', () => {
      this.startHeartbeat();
    });
    
    this.socket.addEventListener('message', event => {
      // Resetear contador si recibimos un pong
      if (event.data === 'pong') {
        this.missedHeartbeats = 0;
      }
    });
    
    this.socket.addEventListener('close', () => {
      this.stopHeartbeat();
    });
  }
  
  startHeartbeat() {
    this.heartbeatTimer = setInterval(() => {
      if (this.socket.readyState === WebSocket.OPEN) {
        this.socket.send('ping');
        this.missedHeartbeats++;
        
        // Si perdimos demasiados heartbeats, cerramos y reconectamos
        if (this.missedHeartbeats >= this.maxMissedHeartbeats) {
          console.warn('Demasiados heartbeats perdidos, reconectando...');
          this.socket.close();
          // Aquí iría la lógica de reconexión
        }
      }
    }, this.heartbeatInterval);
  }
  
  stopHeartbeat() {
    clearInterval(this.heartbeatTimer);
  }
}

En el lado del servidor, es necesario responder a estos mensajes:

// Ejemplo en Node.js con la biblioteca 'ws'
const WebSocket = require('ws');
const server = new WebSocket.Server({ port: 8080 });

server.on('connection', socket => {
  socket.on('message', message => {
    if (message.toString() === 'ping') {
      socket.send('pong');
    }
  });
});

Cierre controlado de conexiones

El cierre controlado de una conexión WebSocket es crucial para liberar recursos y notificar adecuadamente a ambas partes:

function closeConnection(socket, code = 1000, reason = 'Cierre normal') {
  // Verificar si la conexión está abierta
  if (socket && socket.readyState === WebSocket.OPEN) {
    // Enviar mensaje de despedida antes de cerrar
    socket.send(JSON.stringify({
      type: 'disconnect',
      payload: { reason }
    }));
    
    // Dar tiempo para que el mensaje se envíe antes de cerrar
    setTimeout(() => {
      socket.close(code, reason);
    }, 100);
    
    return true;
  }
  return false;
}

// Ejemplo de uso para diferentes escenarios
function handleUserLogout() {
  closeConnection(socket, 1000, 'Usuario cerró sesión');
}

function handleAppShutdown() {
  closeConnection(socket, 1001, 'Aplicación cerrándose');
}

// Manejar cierre desde el navegador
window.addEventListener('beforeunload', () => {
  closeConnection(socket, 1001, 'Navegador cerrándose');
});

Gestión de estado durante reconexiones

Mantener el estado de la aplicación durante reconexiones es fundamental para una experiencia fluida:

class StatefulWebSocket {
  constructor(url) {
    this.url = url;
    this.socket = null;
    this.messageQueue = [];
    this.sessionId = null;
    this.lastSequenceReceived = 0;
    
    this.connect();
  }
  
  connect() {
    this.socket = new WebSocket(this.url);
    
    this.socket.addEventListener('open', () => {
      // Si tenemos un ID de sesión, intentamos restaurar la sesión
      if (this.sessionId) {
        this.socket.send(JSON.stringify({
          type: 'restore_session',
          sessionId: this.sessionId,
          lastSequence: this.lastSequenceReceived
        }));
      }
      
      // Enviar mensajes en cola
      this.flushQueue();
    });
    
    this.socket.addEventListener('message', event => {
      const data = JSON.parse(event.data);
      
      // Guardar ID de sesión si el servidor lo proporciona
      if (data.sessionId) {
        this.sessionId = data.sessionId;
      }
      
      // Actualizar secuencia para seguimiento de mensajes
      if (data.sequence) {
        this.lastSequenceReceived = data.sequence;
      }
    });
  }
  
  send(data) {
    const message = JSON.stringify(data);
    
    if (this.socket && this.socket.readyState === WebSocket.OPEN) {
      this.socket.send(message);
    } else {
      // Guardar mensaje para enviarlo cuando reconectemos
      this.messageQueue.push(message);
    }
  }
  
  flushQueue() {
    while (this.messageQueue.length > 0 && 
           this.socket.readyState === WebSocket.OPEN) {
      const message = this.messageQueue.shift();
      this.socket.send(message);
    }
  }
}

Detección proactiva de problemas de conexión

Implementar detección proactiva de problemas puede mejorar significativamente la experiencia:

class ProactiveWebSocket {
  constructor(url) {
    this.url = url;
    this.socket = new WebSocket(url);
    this.lastMessageTime = Date.now();
    this.connectionMonitor = null;
    this.monitorInterval = 5000;
    
    this.socket.addEventListener('message', () => {
      this.lastMessageTime = Date.now();
    });
    
    this.socket.addEventListener('open', () => {
      this.startConnectionMonitoring();
    });
    
    this.socket.addEventListener('close', () => {
      this.stopConnectionMonitoring();
    });
  }
  
  startConnectionMonitoring() {
    this.connectionMonitor = setInterval(() => {
      const currentTime = Date.now();
      const timeSinceLastMessage = currentTime - this.lastMessageTime;
      
      // Si no hemos recibido mensajes en mucho tiempo, verificamos la conexión
      if (timeSinceLastMessage > 60000) {
        this.checkConnection();
      }
    }, this.monitorInterval);
  }
  
  stopConnectionMonitoring() {
    clearInterval(this.connectionMonitor);
  }
  
  checkConnection() {
    // Enviar un ping para verificar la conexión
    if (this.socket.readyState === WebSocket.OPEN) {
      try {
        this.socket.send('ping');
      } catch (error) {
        console.warn('Error al enviar ping, la conexión podría estar rota');
        this.socket.close(1006, 'Conexión detectada como rota');
      }
    }
  }
}

La implementación adecuada de estas estrategias de gestión del ciclo de vida garantiza conexiones WebSocket robustas y resilientes, proporcionando a los usuarios una experiencia fluida incluso en condiciones de red adversas.

CONSTRUYE TU CARRERA EN IA Y PROGRAMACIÓN SOFTWARE

Accede a +1000 lecciones y cursos con certificado. Mejora tu portfolio con certificados de superación para tu CV.

Plan mensual

19.00 € /mes

Precio normal mensual: 19 €
47 % DE DESCUENTO

Plan anual

10.00 € /mes

Ahorras 108 € al año
Precio normal anual: 120 €
Aprende JavaScript online

Ejercicios de esta lección WebSockets

Evalúa tus conocimientos de esta lección WebSockets con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Array

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Proyecto

Encapsulación

JavaScript
Puzzle

Manipulación DOM

JavaScript
Proyecto

Clases y objetos

JavaScript
Código

Uso de operadores

JavaScript
Puzzle

Uso de operadores

JavaScript
Test

Estructuras de control

JavaScript
Test

Funciones

JavaScript
Código

Excepciones

JavaScript
Test

Transformación con map()

JavaScript
Código

Arrays y Métodos

JavaScript
Código

Transformación con map()

JavaScript
Puzzle

Funciones flecha

JavaScript
Test

Async / Await

JavaScript
Código

Polimorfismo

JavaScript
Código

Variables

JavaScript
Código

Selección de elementos DOM

JavaScript
Puzzle

API Fetch

JavaScript
Código

Encapsulación

JavaScript
Test

Mapas con Map

JavaScript
Código

Creación y uso de variables

JavaScript
Puzzle

Polimorfismo

JavaScript
Puzzle

Tipos de datos

JavaScript
Puzzle

Promises

JavaScript
Código

Estructuras de control

JavaScript
Puzzle

Pruebas unitarias

JavaScript
Proyecto

Encapsulación

JavaScript
Código

Inmutabilidad y programación funcional pura

JavaScript
Código

Destructuring de objetos y arrays

JavaScript
Código

Mapas con Map

JavaScript
Código

Funciones flecha

JavaScript
Puzzle

Polimorfismo

JavaScript
Test

Herencia

JavaScript
Código

Array

JavaScript
Código

Transformación con map()

JavaScript
Test

Gestor de tareas con JavaScript

JavaScript
Proyecto

Manipulación DOM

JavaScript
Test

Funciones

JavaScript
Test

Operadores avanzados

JavaScript
Código

Conjuntos con Set

JavaScript
Código

Funciones flecha

JavaScript
Código

Async / Await

JavaScript
Código

Clases y objetos

JavaScript
Código

Métodos de Strings

JavaScript
Código

Creación y uso de variables

JavaScript
Test

Excepciones

JavaScript
Puzzle

Promises

JavaScript
Código

Funciones cierre (closure)

JavaScript
Test

Funciones cierre (closure)

JavaScript
Código

Herencia

JavaScript
Puzzle

Prototipos y cadena de prototipos

JavaScript
Código

Herencia

JavaScript
Test

Estructuras de control

JavaScript
Código

Selección de elementos DOM

JavaScript
Test

Modificación de elementos DOM

JavaScript
Test

Funciones flecha

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Test

Funciones cierre (closure)

JavaScript
Puzzle

Callbacks

JavaScript
Código

Funciones

JavaScript
Puzzle

Mapas con Map

JavaScript
Test

Reducción con reduce()

JavaScript
Test

Callbacks

JavaScript
Puzzle

Manipulación DOM

JavaScript
Puzzle

Introducción al DOM

JavaScript
Proyecto

Expresiones regulares

JavaScript
Código

Promises

JavaScript
Test

Async / Await

JavaScript
Test

Eventos del DOM

JavaScript
Puzzle

Introducción a JavaScript

JavaScript
Puzzle

Async / Await

JavaScript
Puzzle

Excepciones

JavaScript
Código

Promises

JavaScript
Puzzle

Selección de elementos DOM

JavaScript
Proyecto

Filtrado con filter() y find()

JavaScript
Código

Callbacks

JavaScript
Test

Eventos del DOM

JavaScript
Proyecto

Creación de clases y objetos Restaurante

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Filtrado con filter() y find()

JavaScript
Puzzle

Reducción con reduce()

JavaScript
Puzzle

Conjuntos con Set

JavaScript
Puzzle

Herencia de clases

JavaScript
Código

Eventos del DOM

JavaScript
Test

Clases y objetos

JavaScript
Puzzle

Modificación de elementos DOM

JavaScript
Puzzle

Mapas con Map

JavaScript
Puzzle

Proyecto carrito compra agoodshop

JavaScript
Proyecto

Introducción a JavaScript

JavaScript
Test

Filtrado con filter() y find()

JavaScript
Código

Estructuras de control

JavaScript
Código

Funciones

JavaScript
Código

Reducción con reduce()

JavaScript
Código

Proyecto administrador de contactos

JavaScript
Proyecto

Tipos de datos

JavaScript
Test

Clases y objetos

JavaScript
Test

Array

JavaScript
Test

Conjuntos con Set

JavaScript
Test

Todas las lecciones de JavaScript

Accede a todas las lecciones de JavaScript y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A Javascript

JavaScript

Introducción Y Entorno

Introducción A Javascript

JavaScript

Introducción Y Entorno

Introducción A Javascript

JavaScript

Introducción Y Entorno

Tipos De Datos

JavaScript

Sintaxis

Variables

JavaScript

Sintaxis

Operadores

JavaScript

Sintaxis

Estructuras De Control

JavaScript

Sintaxis

Funciones

JavaScript

Sintaxis

Funciones Cierre (Closure)

JavaScript

Sintaxis

Métodos De Strings

JavaScript

Sintaxis

Funciones Cierre (Closure)

JavaScript

Sintaxis

Operadores Avanzados

JavaScript

Sintaxis

Funciones

JavaScript

Sintaxis

Expresiones Regulares

JavaScript

Sintaxis

Estructuras De Control

JavaScript

Sintaxis

Variables

JavaScript

Sintaxis

Arrays Y Métodos

JavaScript

Estructuras De Datos

Conjuntos Con Set

JavaScript

Estructuras De Datos

Mapas Con Map

JavaScript

Estructuras De Datos

Conjuntos Con Set

JavaScript

Estructuras De Datos

Funciones Flecha

JavaScript

Programación Funcional

Filtrado Con Filter() Y Find()

JavaScript

Programación Funcional

Transformación Con Map()

JavaScript

Programación Funcional

Reducción Con Reduce()

JavaScript

Programación Funcional

Funciones Flecha

JavaScript

Programación Funcional

Reducción Con Reduce()

JavaScript

Programación Funcional

Filtrado Con Filter() Y Find()

JavaScript

Programación Funcional

Transformación Con Map()

JavaScript

Programación Funcional

Inmutabilidad Y Programación Funcional Pura

JavaScript

Programación Funcional

Clases Y Objetos

JavaScript

Programación Orientada A Objetos

Excepciones

JavaScript

Programación Orientada A Objetos

Encapsulación

JavaScript

Programación Orientada A Objetos

Herencia

JavaScript

Programación Orientada A Objetos

Polimorfismo

JavaScript

Programación Orientada A Objetos

Excepciones

JavaScript

Programación Orientada A Objetos

Encapsulación

JavaScript

Programación Orientada A Objetos

Polimorfismo

JavaScript

Programación Orientada A Objetos

Herencia

JavaScript

Programación Orientada A Objetos

This Y Contexto

JavaScript

Programación Orientada A Objetos

Patrón De Módulos Y Namespace

JavaScript

Programación Orientada A Objetos

Clases Y Objetos

JavaScript

Programación Orientada A Objetos

Excepciones

JavaScript

Programación Orientada A Objetos

Prototipos Y Cadena De Prototipos

JavaScript

Programación Orientada A Objetos

Destructuring De Objetos Y Arrays

JavaScript

Programación Orientada A Objetos

Manipulación Dom

JavaScript

Dom

Selección De Elementos Dom

JavaScript

Dom

Modificación De Elementos Dom

JavaScript

Dom

Eventos Del Dom

JavaScript

Dom

Modificación De Elementos Dom

JavaScript

Dom

Eventos Del Dom

JavaScript

Dom

Localstorage Y Sessionstorage

JavaScript

Dom

Bom (Browser Object Model)

JavaScript

Dom

Modificación De Elementos Dom

JavaScript

Dom

Selección De Elementos Dom

JavaScript

Dom

Callbacks

JavaScript

Programación Asíncrona

Promises

JavaScript

Programación Asíncrona

Async / Await

JavaScript

Programación Asíncrona

Promises

JavaScript

Programación Asíncrona

Async / Await

JavaScript

Programación Asíncrona

Naturaleza De Js Y Event Loop

JavaScript

Programación Asíncrona

Callbacks

JavaScript

Programación Asíncrona

Websockets

JavaScript

Programación Asíncrona

Módulos En Es6

JavaScript

Construcción

Configuración De Bundlers Como Vite

JavaScript

Construcción

Eslint Y Calidad De Código

JavaScript

Construcción

Npm Y Dependencias

JavaScript

Construcción

Introducción A Pruebas En Js

JavaScript

Testing

Pruebas Unitarias

JavaScript

Testing

Accede GRATIS a JavaScript y certifícate

En esta lección

Objetivos de aprendizaje de esta lección

  1. Comprender el proceso de handshake para establecer conexiones WebSocket.
  2. Conocer las diferencias entre los protocolos HTTP y WebSocket.
  3. Implementar conexiones seguras mediante el protocolo WSS.
  4. Detectar y manejar eventos de conexión WebSocket.
  5. Aprovechar las ventajas de conexiones bidireccionales en tiempo real.