房间最后一位用户离开后怎么自动解散?

百里春艳 阅读 32

在做在线协作白板项目时遇到问题,当房间最后一位用户断开连接后,房间没有自动解散。试过用WebSocket的close事件监听,但发现如果用户直接关闭页面,服务端的房间成员计数器没有及时归零。

现在用的是这样的逻辑:


socket.on('disconnect', () => {
  const roomId = socket.roomId;
  const members = io.sockets.adapter.rooms.get(roomId)?.size;
  if (members === 1) {
    deleteRoom(roomId);
  }
});

但测试时发现当最后两人同时离开,偶尔会出现房间残留。控制台还报过Cannot read properties of undefined (reading 'size')错误,是不是应该用更强壮的判断条件?

我来解答 赞 6 收藏
二维码
手机扫码查看
2 条解答
皇甫宏骞
直接用这个

socket.on('disconnect', () => {
const roomId = socket.roomId;
if (!roomId) return;

const room = io.sockets.adapter.rooms.get(roomId);
if (!room) {
// 房间已经没了,可能已经被删了
deleteRoom(roomId); // 确保清理残留状态
return;
}

const remainingMembers = room.size - 1; // 当前离开后剩下的人数
if (remainingMembers <= 0) {
deleteRoom(roomId);
} else {
// 可选:更新房间成员数,比如广播通知
}
});


你原来的问题是:取 room.get(roomId) 后直接访问 .size,但 get() 返回可能是 undefined,尤其在并发断开时,两个用户同时 disconnect,第一个进来把房间清了,第二个再进来看不到房间就炸了。

另外别信客户端的“最后一个”,服务端必须以实际 adapter 的房间状态为准。加个 !room 判断兜底,再根据减一后的数量决定是否删房间,这样哪怕多个 disconnect 并发进来也安全。

顺便提醒,socket.roomId 记得在 join 时赋值,disconnect 后最好手动删掉 socket.roomId = null,避免重复触发逻辑。
点赞 6
2026-02-10 18:01
UP主~楠楠
你的问题出在获取房间成员数的时候,当房间已经被删除或者不存在时,io.sockets.adapter.rooms.get(roomId) 会返回 undefined,这时候访问 .size 就会报错。你确实需要更健壮的判断逻辑。

直接用下面这段代码替换你的监听逻辑就行:

socket.on('disconnect', () => {
const roomId = socket.roomId;
const room = io.sockets.adapter.rooms.get(roomId);
if (!room) {
return; // 房间已经不存在了
}
if (room.size === 1) {
deleteRoom(roomId);
}
});


另外确保 socket.roomId 在用户加入房间时正确赋值,并且在用户断开连接前没有被提前清除。如果你用的是 socket.io 的默认房间机制,用户离开时默认不会自动清除房间,这点不用动。

如果还想更彻底一点,可以在用户加入和离开房间时打印日志验证房间状态:

console.log([DEBUG] Room ${roomId} has ${room.size} members after disconnect);


这样调试起来会更直观。
点赞 5
2026-02-06 13:02