Backbone.js изначально проектировался как минималистичный MVC-фреймворк для работы с REST-API. Однако его архитектура событий, модели и коллекции хорошо подходят и для реактивных сценариев, включая работу с WebSocket. Интеграция WebSocket позволяет получать и отправлять данные в реальном времени без постоянного опроса сервера, сохраняя при этом привычную модель Backbone-приложения.
Backbone не навязывает транспортный уровень. Вся работа с сервером сосредоточена вокруг:
Backbone.ModelBackbone.CollectionBackbone.Events)syncWebSocket логично встраивается в приложение как альтернативный или дополнительный канал синхронизации, не нарушая существующую структуру.
Ключевые архитектурные подходы:
Рационально вынести работу с WebSocket в отдельный модуль, который не зависит от конкретных моделей.
var SocketService = _.extend({}, Backbone.Events);
SocketService.connect = function (url) {
this.socket = new WebSocket(url);
this.socket.ono pen = () => {
this.trigger('connected');
};
this.socket.onmess age = (event) => {
var data = JSON.parse(event.data);
this.trigger('message', data);
};
this.socket.oncl ose = () => {
this.trigger('disconnected');
};
this.socket.oner ror = (error) => {
this.trigger('error', error);
};
};
SocketService.send = function (payload) {
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(payload));
}
};
Здесь используется Backbone.Events, что позволяет
подписываться на события WebSocket так же, как на события моделей.
Наиболее распространённый сценарий — получение обновлений конкретных сущностей.
var User = Backbone.Model.extend({
defaults: {
id: null,
name: '',
status: 'offline'
}
});
Обработка входящих сообщений:
SocketService.on('message', function (data) {
if (data.type === 'user:UPDATE') {
usersCollection.get(data.payload.id)
.se t(data.payload);
}
});
Ключевые моменты:
set автоматически генерирует события
changeWebSocket особенно эффективен для коллекций, где данные поступают непрерывно.
var Messages = Backbone.Collection.extend({
model: Message
});
Добавление элементов в реальном времени:
SocketService.on('message', function (data) {
if (data.type === 'message:new') {
messages.add(data.payload);
}
});
Backbone автоматически:
addaddВ классическом Backbone используется Backbone.sync. Для
WebSocket его можно переопределить или расширить.
Backbone.sync = function (method, model, options) {
if (method === 'create' || method === 'UPDATE') {
SocketService.send({
action: method,
entity: model.constructor.name,
data: model.toJSON()
});
options.success();
}
};
Такой подход:
WebSocket позволяет не только отправлять изменения, но и получать подтверждения или откаты.
Пример обработки ответа сервера:
SocketService.on('message', function (data) {
if (data.type === 'model:ack') {
var model = collection.get(data.id);
model.se t({ synced: true });
}
if (data.type === 'model:error') {
model.set({ error: data.message });
}
});
Это особенно важно для:
Backbone.View удобно использовать для управления подписками.
var ChatView = Backbone.View.extend({
initialize: function () {
this.listenTo(SocketService, 'message', this.onMessage);
},
remove: function () {
this.stopListening();
Backbone.View.prototype.remove.call(this);
}
});
Преимущества:
В реальных приложениях WebSocket передаёт множество типов событий. Эффективная стратегия — маршрутизация сообщений.
var handlers = {
'user:UPDATE': handleUserUpdate,
'message:new': handleNewMessage,
'room:join': handleRoomJoin
};
SocketService.on('message', function (data) {
var handler = handlers[data.type];
if (handler) handler(data.payload);
});
Это снижает связность и упрощает поддержку.
WebSocket может взаимодействовать с роутингом приложения.
SocketService.on('message', function (data) {
if (data.type === 'session:expired') {
Backbone.history.navigate('login', { trigger: true });
}
});
Таким образом сервер способен управлять навигацией клиента через события.
Backbone не имеет встроенной логики повторного подключения, но WebSocket-сервис легко расширяется.
SocketService.reconnect = function (url) {
setTimeout(() => {
this.connect(url);
}, 3000);
};
И связка с коллекциями:
SocketService.on('connected', function () {
users.fetch();
});
Это позволяет:
WebSocket не обязательно заменяет REST полностью. Часто используется гибридный подход:
fetch через HTTP для начальной загрузкиsave через WebSocket или HTTP в зависимости от типа
данныхBackbone поддерживает это без изменения базовой структуры.
Backbone предоставляет механизм {silent: true} для
пакетных обновлений.
model.se t(data, { silent: true });
model.trigger('change');
Это полезно при массовых WebSocket-обновлениях:
Вынос WebSocket в отдельный сервис упрощает тестирование:
SocketServicetriggerSocketService.trigger('message', mockData);
Интеграция WebSocket в Backbone.js опирается не на расширение фреймворка, а на его сильные стороны:
WebSocket становится ещё одним источником данных, который органично вписывается в существующую архитектуру без нарушения принципов Backbone.