WebSockets в JavaScript: когда «живой» сайт — это не магия, а код
Вы когда-нибудь задумывались, как работают онлайн-чаты, биржевые котировки в реальном времени или многопользовательские браузерные игры? Секрет прост и элегантен — WebSockets в JavaScript. Эта технология превращает статичный веб-сайт в живой организм, который мгновенно реагирует на действия других пользователей.
В этой статье мы не просто разберём теорию. Мы напишем настоящий чат с нуля, научимся обрабатывать ошибки и поймём, почему real-time приложения на WebSockets работают быстрее, чем старый добрый AJAX с polling'ом. Пристегнитесь — будет интересно.
Почему HTTP не подходит для real-time? (Краткий ликбез)
Обычный HTTP работает по принципу «запрос-ответ». Клиент просит — сервер отвечает. Если сервер хочет что-то сказать сам (например, «пришло новое сообщение»), ему приходится ждать, пока клиент снова спросит. Это напоминает переписку почтовыми голубями — медленно и неэффективно.
Разработчики придумывали обходные пути:
- Polling — клиент дёргает сервер каждые 5 секунд: «Ну что, есть новости?»
- Long polling — сервер держит соединение открытым, пока не появится ответ (но это всё равно однонаправленный канал).
И тут на сцену выходят WebSockets. Представьте, что вы открыли телефонную линию между браузером и сервером. Оба могут говорить в любой момент, одновременно, без задержек на «поднятие трубки». Это и есть магия JavaScript WebSocket API.
Как работает WebSocket: протокол, рукопожатие, сообщения
Технически WebSocket — это отдельный протокол (ws:// или wss:// для шифрованного соединения). Всё начинается с HTTP-рукопожатия:
- Клиент отправляет обычный HTTP-запрос с заголовком
Upgrade: websocket. - Сервер отвечает: «101 Switching Protocols» — и соединение «апгрейдится» до WebSocket.
- Дальше — полный дуплекс: данные летят в обе стороны в виде фреймов (текст или бинарные данные).
В браузере для работы с WebSocket используется встроенный объект WebSocket. Никаких дополнительных библиотек не нужно — чистый JavaScript WebSocket работает из коробки во всех современных браузерах.
Пишем первый real-time чат на JavaScript
Давайте создадим простой чат. Серверную часть напишем на Node.js с библиотекой ws (самая популярная для WebSocket Node.js), клиент — на чистом JavaScript.
Шаг 1. Установка сервера
npm init -y
npm install ws
Шаг 2. Серверный код (server.js)
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log('Новый пользователь подключился');
// Отправляем приветствие новому клиенту
ws.send(JSON.stringify({
type: 'system',
message: 'Добро пожаловать в чат!'
}));
// Получаем сообщения от клиента
ws.on('message', function incoming(data) {
const message = JSON.parse(data);
console.log('Получено:', message);
// Рассылаем сообщение всем подключенным клиентам
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({
type: 'message',
user: message.user,
text: message.text,
time: new Date().toLocaleTimeString()
}));
}
});
});
// Обрабатываем отключение
ws.on('close', function() {
console.log('Пользователь отключился');
});
});
console.log('Сервер запущен на ws://localhost:8080');
Шаг 3. Клиентский код (index.html)
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Real-time Чат на WebSockets</title>
<style>
#chat { width: 500px; margin: 20px auto; font-family: Arial; }
#messages { height: 300px; overflow-y: scroll; border: 1px solid #ccc; padding: 10px; }
#input-area { display: flex; margin-top: 10px; }
#message-input { flex: 1; padding: 10px; }
#send-btn { padding: 10px 20px; background: #007bff; color: white; border: none; cursor: pointer; }
</style>
</head>
<body>
<div id="chat">
<h2>Real-time Чат</h2>
<div id="messages"></div>
<div id="input-area">
<input type="text" id="message-input" placeholder="Введите сообщение..." />
<button id="send-btn">Отправить</button>
</div>
</div>
<script>
const ws = new WebSocket('ws://localhost:8080');
const messagesDiv = document.getElementById('messages');
const input = document.getElementById('message-input');
const sendBtn = document.getElementById('send-btn');
// При подключении
ws.onopen = function() {
console.log('Соединение установлено');
addMessage('system', 'Вы подключились к чату');
};
// При получении сообщения
ws.onmessage = function(event) {
const data = JSON.parse(event.data);
addMessage(data.type, data.message || data.text, data.user, data.time);
};
// При ошибке
ws.onerror = function(error) {
console.error('Ошибка WebSocket:', error);
addMessage('system', '⚠️ Ошибка соединения');
};
// При закрытии
ws.onclose = function() {
console.log('Соединение закрыто');
addMessage('system', '❌ Соединение потеряно');
};
// Отправка сообщения
sendBtn.addEventListener('click', function() {
const text = input.value.trim();
if (text) {
ws.send(JSON.stringify({
user: 'Пользователь',
text: text
}));
input.value = '';
}
});
// Отправка по Enter
input.addEventListener('keypress', function(e) {
if (e.key === 'Enter') sendBtn.click();
});
function addMessage(type, content, user, time) {
const div = document.createElement('div');
if (type === 'system') {
div.style.color = '#888';
div.style.fontStyle = 'italic';
div.textContent = content;
} else {
div.innerHTML = `<strong>${user}</strong> [${time}]: ${content}`;
}
messagesDiv.appendChild(div);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
</script>
</body>
</html>
Продвинутые техники: бинарные данные и reconnect
Отправка бинарных данных через WebSocket
WebSocket умеет передавать не только текст, но и бинарные данные
Блоги
Рекомендаций по книгам
Читайте также