如何实现订阅模式
¥How to implement a subscription model
默认情况下,即使另一端没有注册事件处理程序,事件也会通过线路发送。
¥By default, events are sent over the wire even if there is no registered event handler on the other side.
你可以使用捕获所有监听器捕获那些丢失的事件处理程序:
¥You can catch those missing event handlers with a catch-all listener:
socket.onAny((event) => {
if (socket.listeners(event).length === 0) {
console.log(`missing handler for event ${event}`);
}
});
参考:onAny()
方法
¥Reference: onAny()
method
要仅接收特定事件的列表(例如,如果应用的一部分只需要少数事件),你可以实现订阅模型:
¥To only receive a list of specific events (for example, if a part of your application only needs a handful of events), you can implement a subscription model:
客户端
¥Client
const subscriptions = [];
function subscribe(topic) {
subscriptions.push(topic);
if (socket.connected) {
socket.emit("subscribe", [topic]);
}
}
function unsubscribe(topic) {
const i = subscriptions.indexOf(topic);
if (i !== -1) {
subscriptions.splice(i, 1);
if (socket.connected) {
socket.emit("unsubscribe", topic);
}
}
}
// restore the subscriptions upon reconnection
socket.on("connect", () => {
if (subscriptions.length && !socket.recovered) {
socket.emit("subscribe", subscriptions);
}
});
subscribe("foo");
服务器
¥Server
io.on("connection", (socket) => {
socket.on("subscribe", (topics) => {
socket.join(topics);
});
socket.on("unsubscribe", (topic) => {
socket.leave(topic);
});
// send an event only to clients that have shown interest in the "foo" topic
io.to("foo").emit("foo");
});
补充注意
¥Additional notes
订阅列表
¥List of subscriptions
我们可以在客户端使用 ES6 Set 进行订阅:
¥We could have used a ES6 Set for the subscriptions on the client side:
const subscriptions = new Set();
function subscribe(topic) {
subscriptions.add(topic);
if (socket.connected) {
socket.emit("subscribe", [topic]);
}
}
function unsubscribe(topic) {
const deleted = subscriptions.delete(topic);
if (deleted && socket.connected) {
socket.emit("unsubscribe", topic);
}
}
// restore the subscriptions upon reconnection
socket.on("connect", () => {
if (subscriptions.size) {
socket.emit("subscribe", [...subscriptions]);
}
});
哪个更干净(例如,不需要处理重复的订阅),但如果你需要定位 旧平台,则需要填充程序。
¥Which is cleaner (no need to handle duplicate subscriptions, for example) but would require a polyfill if you need to target old platforms.
连接状态恢复
¥Connection state recovery
在 "connect" 处理程序中:
¥In the "connect" handler:
socket.on("connect", () => {
if (subscriptions.length && !socket.recovered) {
socket.emit("subscribe", subscriptions);
}
});
!socket.recovered
条件与 连接状态恢复功能 相关。
¥The !socket.recovered
condition is related to the Connection state recovery feature.
如果连接状态成功恢复,则订阅(服务器端的房间)将自动恢复。
¥If the connection state was successfully recovered, then the subscriptions (the rooms on the server side) will be automatically restored.
¥Reference: socket.recovered
attribute