SocketIO+NodeJS双Chrome实例新用户加入提示不同步问题
问题原因
你遇到的问题核心是对socket.broadcast.emit()的接口行为理解有误:
- 该API只会向除当前触发事件的socket之外,当下已经建立连接的客户端推送事件,不会给之后才连接的客户端补发历史消息,也不会给触发事件的客户端自己发消息。
- 你打开第一个Chrome页面输入昵称触发
newuserjoined事件时,第二个Chrome页面还没打开、没有和服务端建立连接,收不到这次广播。等第二个页面加载完成连接服务端、输入昵称触发事件时,第一个页面已经在线,所以能收到第二个用户的加入广播,反过来第二个页面收不到第一个用户早先发过的加入通知。
修复步骤
服务端代码调整
新客户端连接成功时,主动把当前所有在线用户列表推送给新客户端,原有新用户加入的广播逻辑保留即可,补充后的完整服务端代码:
const io = require('socket.io')(8000, { cors: { origin: "*" } }); const users = {}; io.on('connection', socket => { // 新连接建立后,先推送当前已在线的所有用户列表给新客户端 socket.emit('existing-users', Object.values(users)); socket.on('newuserjoined', name=>{ console.log('New User', name); users[socket.id] = name; // 保留原有逻辑:通知其他所有在线用户有新用户加入 socket.broadcast.emit('user-joined', name); }) socket.on('sendmessage', message => { console.log(message); socket.broadcast.emit('chat-message', message); }) // 可选补充:用户断开连接时通知其他人 socket.on('disconnect', () => { const leaveUser = users[socket.id]; delete users[socket.id]; if(leaveUser) socket.broadcast.emit('user-left', leaveUser); }) });
客户端代码调整
新增对existing-users事件的监听,渲染早于当前用户进入聊天室的在线用户提示;另外修正原代码里他人消息/提示全部放在右侧的UI问题,把他人相关的内容放到左侧做区分,补充后核心客户端代码:
const socket = io('http://localhost:8000'); const messageform = document.getElementById('form'); const inmessage = document.getElementById('messageinput'); const messagecontainer = document.querySelector('.container'); socket.on('chat-message', data =>{ console.log(data); append(`${data.name}: ${data.content}`, 'left'); }); messageform.addEventListener('submit', e=>{ e.preventDefault() const message = inmessage.value // 发消息时携带用户名,解决多用户聊天分不清发送者的问题 socket.emit('sendmessage', { name: uname, content: message }) append(`You: ${message}`, 'right') inmessage.value = '' }); const append = (message, position)=>{ const messageElement = document.createElement('div'); messageElement.innerText = message; messageElement.classList.add('message'); messageElement.classList.add(position); messagecontainer.append(messageElement); } const uname = prompt("Enter your name?"); append(`You joined`, 'right') socket.emit('newuserjoined', uname) // 接收服务端推送的已有在线用户列表,逐个渲染提示 socket.on('existing-users', userList => { userList.forEach(name => { append(`${name} is already in the chat`, 'left'); }) }) socket.on('user-joined', name=>{ append(`${name} joined the chat`, 'left'); }) // 可选:监听用户离开事件 socket.on('user-left', name => { append(`${name} left the chat`, 'left'); })
补充说明
原代码发送聊天消息时没有携带发送者昵称,多用户场景下无法区分消息发送方,上述修复代码已经同步补上该逻辑。如果需要做消息持久化、历史消息加载,可以在服务端用数组/数据库存储消息记录,新用户连接时和在线用户列表一起推送给客户端即可。
内容的提问来源于stack exchange,提问作者Muhammad Kashif
相关产品推荐
相关产品推荐

