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ícateEstablecimiento 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:
- 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 protocoloConnection: Upgrade
- Confirma la intención de actualizar la conexiónSec-WebSocket-Key
- Clave aleatoria generada por el clienteSec-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 delSec-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.
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
Modificación de elementos DOM
Encapsulación
Manipulación DOM
Clases y objetos
Uso de operadores
Uso de operadores
Estructuras de control
Funciones
Excepciones
Transformación con map()
Arrays y Métodos
Transformación con map()
Funciones flecha
Async / Await
Polimorfismo
Variables
Selección de elementos DOM
API Fetch
Encapsulación
Mapas con Map
Creación y uso de variables
Polimorfismo
Tipos de datos
Promises
Estructuras de control
Pruebas unitarias
Encapsulación
Inmutabilidad y programación funcional pura
Destructuring de objetos y arrays
Mapas con Map
Funciones flecha
Polimorfismo
Herencia
Array
Transformación con map()
Gestor de tareas con JavaScript
Manipulación DOM
Funciones
Operadores avanzados
Conjuntos con Set
Funciones flecha
Async / Await
Clases y objetos
Métodos de Strings
Creación y uso de variables
Excepciones
Promises
Funciones cierre (closure)
Funciones cierre (closure)
Herencia
Prototipos y cadena de prototipos
Herencia
Estructuras de control
Selección de elementos DOM
Modificación de elementos DOM
Funciones flecha
Filtrado con filter() y find()
Funciones cierre (closure)
Callbacks
Funciones
Mapas con Map
Reducción con reduce()
Callbacks
Manipulación DOM
Introducción al DOM
Expresiones regulares
Promises
Async / Await
Eventos del DOM
Introducción a JavaScript
Async / Await
Excepciones
Promises
Selección de elementos DOM
Filtrado con filter() y find()
Callbacks
Eventos del DOM
Creación de clases y objetos Restaurante
Reducción con reduce()
Filtrado con filter() y find()
Reducción con reduce()
Conjuntos con Set
Herencia de clases
Eventos del DOM
Clases y objetos
Modificación de elementos DOM
Mapas con Map
Proyecto carrito compra agoodshop
Introducción a JavaScript
Filtrado con filter() y find()
Estructuras de control
Funciones
Reducción con reduce()
Proyecto administrador de contactos
Tipos de datos
Clases y objetos
Array
Conjuntos con Set
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
Introducción Y Entorno
Introducción A Javascript
Introducción Y Entorno
Introducción A Javascript
Introducción Y Entorno
Tipos De Datos
Sintaxis
Variables
Sintaxis
Operadores
Sintaxis
Estructuras De Control
Sintaxis
Funciones
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Métodos De Strings
Sintaxis
Funciones Cierre (Closure)
Sintaxis
Operadores Avanzados
Sintaxis
Funciones
Sintaxis
Expresiones Regulares
Sintaxis
Estructuras De Control
Sintaxis
Variables
Sintaxis
Arrays Y Métodos
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Mapas Con Map
Estructuras De Datos
Conjuntos Con Set
Estructuras De Datos
Funciones Flecha
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Funciones Flecha
Programación Funcional
Reducción Con Reduce()
Programación Funcional
Filtrado Con Filter() Y Find()
Programación Funcional
Transformación Con Map()
Programación Funcional
Inmutabilidad Y Programación Funcional Pura
Programación Funcional
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Encapsulación
Programación Orientada A Objetos
Polimorfismo
Programación Orientada A Objetos
Herencia
Programación Orientada A Objetos
This Y Contexto
Programación Orientada A Objetos
Patrón De Módulos Y Namespace
Programación Orientada A Objetos
Clases Y Objetos
Programación Orientada A Objetos
Excepciones
Programación Orientada A Objetos
Prototipos Y Cadena De Prototipos
Programación Orientada A Objetos
Destructuring De Objetos Y Arrays
Programación Orientada A Objetos
Manipulación Dom
Dom
Selección De Elementos Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Modificación De Elementos Dom
Dom
Eventos Del Dom
Dom
Localstorage Y Sessionstorage
Dom
Bom (Browser Object Model)
Dom
Modificación De Elementos Dom
Dom
Selección De Elementos Dom
Dom
Callbacks
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Promises
Programación Asíncrona
Async / Await
Programación Asíncrona
Naturaleza De Js Y Event Loop
Programación Asíncrona
Callbacks
Programación Asíncrona
Websockets
Programación Asíncrona
Módulos En Es6
Construcción
Configuración De Bundlers Como Vite
Construcción
Eslint Y Calidad De Código
Construcción
Npm Y Dependencias
Construcción
Introducción A Pruebas En Js
Testing
Pruebas Unitarias
Testing
En esta lección
Objetivos de aprendizaje de esta lección
- Comprender el proceso de handshake para establecer conexiones WebSocket.
- Conocer las diferencias entre los protocolos HTTP y WebSocket.
- Implementar conexiones seguras mediante el protocolo WSS.
- Detectar y manejar eventos de conexión WebSocket.
- Aprovechar las ventajas de conexiones bidireccionales en tiempo real.