Server-Sent Events

Server-Sent Events (SSE) представляют собой механизм однонаправленной связи от сервера к клиенту, позволяющий получать обновления в реальном времени без необходимости постоянного опроса. В контексте FAST Element SSE могут быть интегрированы для динамического обновления интерфейса компонентов без перезагрузки страницы.


Подключение SSE в FAST Element

Для использования SSE в компонентах FAST Element создается объект EventSource. Он позволяет подписаться на поток сообщений с сервера и обрабатывать их через события message, open и error.

import { FASTElement, html, css } from "@microsoft/fast-element";

const template = html<MySseComponent>`
  <div>
    <h2>Обновления сервера:</h2>
    <ul>
      ${x => x.messages.map(msg => html`<li>${msg}</li>`)}
    </ul>
  </div>
`;

const styles = css`
  h2 {
    color: #333;
    font-family: Arial, sans-serif;
  }
  ul {
    padding-left: 20px;
  }
`;

export class MySseComponent extends FASTElement {
  messages = [];

  connectedCallback() {
    super.connectedCallback();
    this.initSse();
  }

  initSse() {
    const source = new EventSource("/sse-endpoint");

    source.ono pen = () => {
      console.log("Соединение с сервером установлено");
    };

    source.onmess age = (event) => {
      this.messages = [...this.messages, event.data];
      this.$emit("messages-changed");
    };

    source.oner ror = (error) => {
      console.error("Ошибка SSE:", error);
      source.close();
    };
  }
}

FASTElement.define({ name: "my-sse-component", template, styles, elementClass: MySseComponent });

Ключевые моменты:

  • EventSource автоматически повторно подключается при разрыве соединения.
  • Метод onmessage используется для обработки каждой новой порции данных.
  • Для реактивного обновления шаблона свойства компонента должны быть привязаны через функции в шаблоне.

Обработка различных событий

SSE предоставляет несколько типов событий:

  1. open — срабатывает при успешном подключении к серверу.
  2. message — получает данные от сервера. Данные могут быть в формате строки, JSON или любом другом, если они корректно сериализованы.
  3. error — срабатывает при проблемах соединения, например, при недоступности сервера.

Можно добавлять кастомные события, используя метод addEventListener:

source.addEventListener("custom-event", (event) => {
  console.log("Кастомное событие:", event.data);
});

Интеграция SSE с реактивностью FAST Element

Для того чтобы обновления от SSE автоматически отражались в DOM, необходимо использовать реактивные свойства компонентов. FAST Element позволяет легко связывать свойства с шаблоном:

<ul>
  ${x => x.messages.map(msg => html`<li>${msg}</li>`)}
</ul>

При изменении массива messages можно уведомлять FAST о необходимости обновления шаблона через $emit с событием "messages-changed", либо использовать Observable свойства:

import { observable } from "@microsoft/fast-element";

export class MySseComponent extends FASTElement {
  @observable messages = [];
}

Серверная сторона SSE

На сервере заголовки должны быть следующими:

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

Пример простого сервера на Node.js с использованием Express:

const express = require("express");
const app = express();

app.get("/sse-endpoint", (req, res) => {
  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  let counter = 0;

  const interval = setInterval(() => {
    counter++;
    res.write(`data: Сообщение ${counter}\n\n`);
  }, 2000);

  req.on("close", () => {
    clearInterval(interval);
  });
});

app.listen(3000);

Особенности:

  • Каждое сообщение отделяется двойным переносом строки \n\n.
  • SSE поддерживает только однонаправленную передачу данных — от сервера к клиенту.
  • Соединение может быть долгоживущим, но стоит контролировать таймауты и повторное подключение.

Форматы данных и сериализация

SSE передает данные как строки. Для передачи объектов рекомендуется использовать JSON:

res.write(`data: ${JSON.stringify({ text: "Новое событие", timestamp: Date.now() })}\n\n`);

На клиенте данные можно парсить:

source.onmess age = (event) => {
  const payload = JSON.parse(event.data);
  this.messages = [...this.messages, `${payload.timestamp}: ${payload.text}`];
};

Особенности работы с FAST Element

  • Долговременные соединения SSE могут потребовать закрытия при размонтировании компонента (disconnectedCallback), чтобы избежать утечек памяти:
disconnectedCallback() {
  if (this.source) {
    this.source.close();
  }
  super.disconnectedCallback();
}
  • Привязка свойств и массивов через шаблон позволяет автоматически перерисовывать DOM без дополнительных методов рендеринга.
  • SSE идеально подходит для динамических списков уведомлений, логов в реальном времени, обновления данных на дашбордах.

Поддержка и ограничения

  • SSE работает во всех современных браузерах, кроме старых версий IE.
  • Ограничение на количество одновременных соединений обычно устанавливается браузером (обычно 6-10 на домен).
  • Не поддерживает двунаправленную связь, для этого рекомендуется использовать WebSocket.

Хотя SSE является простым в реализации и нативно поддерживается браузером, в FAST Element его использование особенно удобно благодаря реактивной системе и декларативному связыванию шаблонов с данными. Это позволяет создавать динамические, интерактивные интерфейсы с минимальной нагрузкой на клиентскую логику.