Server-Sent Events в JavaScript: Реальное время без WebSocket

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Server-Sent Events и зачем они вам нужны?

Представьте: вы открыли сайт с курсами валют, и курс доллара меняется прямо на глазах — без обновления страницы, без нажатия кнопок. Или вы ждёте результат обработки большого файла на сервере, и вдруг появляется строка: «Готово на 70%». Как это работает? Один из самых элегантных способов — Server-Sent Events (SSE).

SSE — это технология, которая позволяет серверу самостоятельно отправлять данные клиенту в любой момент, как только они появляются. В отличие от WebSocket, SSE работает только в одну сторону — от сервера к клиенту. Но в этом и его суперсила: он невероятно прост, эффективен и идеально подходит для задач, где клиенту нужно лишь получать обновления.

В этой статье мы разберёмся, как использовать Server-Sent Events в JavaScript, напишем рабочий код и поймём, когда SSE — лучший выбор, а когда лучше посмотреть в сторону WebSocket. Готовы? Поехали!

Как работают Server-Sent Events (SSE)?

Технически SSE — это просто HTTP-соединение, которое сервер не закрывает после отправки ответа. Вместо этого он шлёт данные частями, используя специальный формат text/event-stream. Клиент (браузер) слушает это соединение через объект EventSource и генерирует события при получении каждого нового сообщения.

Вот как выглядит типичный ответ сервера:

data: {"message": "Привет!", "timestamp": 1700000000}

data: {"message": "Новое уведомление", "timestamp": 1700000001}

Каждое сообщение начинается с data:, за которым следует пробел и само содержимое. Сообщения разделяются двумя символами новой строки \n\n. Сервер может также отправлять идентификаторы (id:) и типы событий (event:), но минимальный набор — это data.

Клиентская часть ещё проще:

const eventSource = new EventSource('/events');

eventSource.onmessage = (e) => {
    console.log('Получены данные:', e.data);
};

eventSource.onerror = (e) => {
    console.error('Ошибка соединения', e);
};

Всё! Никаких сложных рукопожатий, никаких библиотек — браузер сам переподключается при разрыве, сам обрабатывает потерю связи. Это и есть главная магия Server-Sent Events.

SSE vs WebSocket: когда что выбирать?

Часто новички думают: «Раз SSE проще, значит, он всегда лучше». Но это не так. У каждой технологии своя ниша. Давайте сравним.

Характеристика SSE WebSocket
Направление данных Только сервер → клиент Двустороннее
Простота реализации Очень простая (нативный браузер) Средняя (нужна библиотека)
Автоматическое переподключение Встроенное Нужно реализовывать вручную
Поддержка браузерами Все современные (кроме IE) Все современные
Протокол HTTP (проходит через прокси) ws:// (может блокироваться)

Когда использовать SSE?

  • Лента новостей, курс валют, котировки акций
  • Push-уведомления от сервера
  • Мониторинг выполнения задач (прогресс-бары)
  • Логирование в реальном времени

Когда нужен WebSocket?

  • Онлайн-игры, чаты, редакторы кода (нужна двусторонняя связь)
  • Приложения, где клиент активно отправляет данные

Если ваша задача — получать обновления от сервера, и вам не нужно ничего отправлять обратно, Server-Sent Events — идеальный выбор. Он проще, легче и не требует дополнительных библиотек.

Пишем клиент на JavaScript с EventSource

Давайте создадим полноценный пример. Предположим, у нас есть сервер, который каждую секунду присылает случайное число. Напишем клиент, который будет отображать эти числа и считать статистику.

// client.js
const url = 'http://localhost:3000/stream';
const eventSource = new EventSource(url);

// Обработчик общих сообщений
eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data);
    const container = document.getElementById('numbers');
    const newItem = document.createElement('li');
    newItem.textContent = `Получено: ${data.value} в ${new Date(data.timestamp * 1000).toLocaleTimeString()}`;
    container.appendChild(newItem);
};

// Обработчик специального события "close"
eventSource.addEventListener('close', () => {
    console.log('Сервер завершил поток');
    eventSource.close();
});

// Обработчик ошибок
eventSource.onerror = (err) => {
    console.error('Ошибка SSE:', err);
    // Браузер автоматически попробует переподключиться через 3 секунды
};

// Кнопка для принудительного закрытия
document.getElementById('stop').addEventListener('click', () => {
    eventSource.close();
    console.log('Соединение закрыто вручную');
});

Обратите внимание на метод addEventListener. С помощью него можно ловить именованные события, которые сервер отправляет с полем event:. Например:

event: close
data: {"reason": "Задача завершена"}

Также полезно знать, что EventSource автоматически передаёт в заголовке запроса Last-Event-ID, если сервер отправлял id:. Это позволяет восстановить поток с последнего полученного сообщения после

Блоги

Рекомендаций по книгам