В библиотеке STOMP.js вся модель взаимодействия строится вокруг событийно-ориентированного подхода, где основной поток управления передаётся через набор колбэков и обработчиков, реагирующих на жизненный цикл соединения, подписок и входящих сообщений. Такой подход позволяет отделить транспортный уровень (WebSocket/STOMP) от бизнес-логики приложения и строить масштабируемые системы обмена сообщениями.
STOMP-клиент представляет собой конечный автомат, проходящий через состояния подключения, активной работы и отключения. Каждое состояние сопровождается набором событий, которые перехватываются через функции-обработчики.
Ключевая особенность модели заключается в том, что практически любое действие в STOMP.js реализуется через callback:
Эта структура делает поведение клиента предсказуемым и управляемым, особенно в асинхронной среде браузера.
Основной входной точкой после установления соединения является обработчик успешного подключения.
const client = new StompJs.Client({
brokerURL: "ws://localhost:15674/ws",
onConnect: (frame) => {
console.log("Соединение установлено");
}
});
Аргумент frame содержит данные протокольного ответа
сервера:
Этот объект используется для диагностики и адаптации поведения клиента под серверные условия.
Основной поток данных в STOMP.js поступает через подписки. Каждая подписка получает callback, который вызывается при поступлении сообщения.
const subscription = client.subscribe("/topic/orders", (message) => {
console.log(message.body);
});
Объект сообщения включает:
body — полезная нагрузка (строка или сериализованный
JSON)headers — метаданные сообщенияack — функция подтверждения доставки (если включён
режим ack)Часто тело сообщения требует десериализации:
client.subscribe("/topic/orders", (message) => {
const data = JSON.parse(message.body);
processOrder(data);
});
Колбэк выполняет роль централизованной точки обработки входящего потока данных.
При использовании режима подтверждения вручную (client-ack) появляется дополнительный уровень управления обработкой сообщений.
client.subscribe(
"/queue/tasks",
(message) => {
try {
handleTask(JSON.parse(message.body));
message.ack();
} catch (e) {
message.nack();
}
},
{ ack: "client" }
);
ack() — подтверждает успешную обработкуnack() — сигнализирует о необходимости повторной
доставкиЭти методы являются частью callback-цепочки обработки и напрямую влияют на семантику доставки сообщений.
Ошибки протокольного уровня STOMP обрабатываются через отдельный callback.
const client = new StompJs.Client({
brokerURL: "ws://localhost:15674/ws",
onStompError: (frame) => {
console.error("STOMP ошибка:", frame.headers["message"]);
console.error("Детали:", frame.body);
}
});
Чаще всего обрабатываются:
Этот callback не связан с транспортными ошибками WebSocket, что важно для разделения уровней диагностики.
Ошибки на уровне транспортного соединения обрабатываются отдельно.
client.onWebSocketEr ror = (event) => {
console.error("WebSocket ошибка:", event);
};
Этот callback вызывается при:
Он не содержит STOMP-данных и работает на уровне сырого канала связи.
Закрытие соединения также сопровождается отдельным событием.
client.onWebSocketCl ose = () => {
console.log("Соединение закрыто");
};
Этот callback используется для:
Он завершает жизненный цикл активного подключения.
STOMP.js поддерживает автоматическое переподключение, управляемое параметрами клиента.
const client = new StompJs.Client({
reconnectDelay: 5000
});
Хотя это не callback в строгом смысле, поведение переподключения часто сопровождается дополнительными обработчиками состояния.
client.onConn ect = () => {
console.log("Подключено");
};
client.onDisconn ect = () => {
console.log("Отключено");
};
Эти функции формируют базовую модель управления состоянием соединения.
Каждая подписка в STOMP.js возвращает объект, содержащий метод
unsubscribe, который также может быть обёрнут логикой
callback-управления.
const sub = client.subscribe("/topic/updates", handler);
// позже
sub.unsubscribe();
Колбэк подписки в этом случае является точкой привязки жизненного цикла данных.
В сложных приложениях callback подписки часто заменяется диспетчеризацией:
client.subscribe("/topic/events", (message) => {
const event = JSON.parse(message.body);
switch (event.type) {
case "create":
handleCreate(event);
break;
case "update":
handleUpdate(event);
break;
case "delete":
handleDelete(event);
break;
}
});
Такой подход превращает единый callback в маршрутизатор событий.
Callback-архитектура STOMP.js позволяет строить цепочки обработки:
const parse = (msg) => JSON.parse(msg.body);
const validate = (data) => data && data.id;
client.subscribe("/topic/data", (message) => {
const data = parse(message);
if (!validate(data)) return;
process(data);
});
Хотя callback подписки выглядит синхронным, он часто содержит асинхронные операции:
client.subscribe("/topic/jobs", async (message) => {
const job = JSON.parse(message.body);
await processAsync(job);
});
Особенности:
Ошибки, возникающие внутри обработчиков сообщений, не всегда перехватываются библиотекой автоматически.
client.subscribe("/topic/test", (message) => {
throw new Error("Ошибка обработки");
});
Такие ошибки необходимо оборачивать вручную:
client.subscribe("/topic/test", (message) => {
try {
handle(message);
} catch (e) {
console.error("Ошибка в обработчике:", e);
}
});
Вся система STOMP.js фактически является реактивной:
Эта модель позволяет строить приложения, где поток данных управляет логикой, а не наоборот.