Socket.io多次触发emit事件:加入多房间后消息重复发送如何解决
问题根因
bug来自客户端事件监听器的重复绑定:每次调用joinRoom函数时,都会通过nsSocket.on('updateMessage', ...)新增一个独立的事件回调,没有移除之前绑定的旧回调。你先后加入3个房间就绑定了3个回调,收到updateMessage事件时3个回调会同时执行,自然就会渲染3条相同消息。
服务端逻辑没有问题,不需要改动。
修复方案
方案1(推荐):全局只绑定一次事件监听
把updateMessage的监听逻辑从joinRoom里移出来,全局只绑定一次即可,不需要每次进入房间重复绑定:
// 全局仅绑定一次updateMessage监听 nsSocket.on('updateMessage', payload => { messages.innerHTML += ` <li> <div class="user-image"> <img src="https://via.placeholder.com/30" /> </div> <div class="user-message"> <div class="user-name-time">rbunch <span>${new Date(Date.now()).toDateString()}</span></div> <div class="message-text">${payload.data}</div> </div> </li> ` }) function joinRoom(roomName) { // 这行removeEventListener是无效代码,每次传入的箭头函数是全新引用,无法匹配之前绑定的回调,可直接删除 // form.removeEventListener('submit', e => submitMsg(e)) nsSocket.emit('joinRoom', {data: {nsp: nsSocket.nsp, roomName}}, numberOfMember => { document.getElementById('current-room').innerHTML = `<span class="curr-room-text">${roomName}</span> <span class="curr-room-num-users">Users: ${numberOfMember}<span class="glyphicon glyphicon-user"></span></span>` }) messages.innerHTML = '' // 删掉这里重复绑定的updateMessage监听逻辑 }
方案2:绑定新监听前先移除旧监听
如果你的业务逻辑确实需要每次进入房间重新绑定回调,就先调用off移除旧的监听:
function joinRoom(roomName) { nsSocket.emit('joinRoom', {data: {nsp: nsSocket.nsp, roomName}}, numberOfMember => { document.getElementById('current-room').innerHTML = `<span class="curr-room-text">${roomName}</span> <span class="curr-room-num-users">Users: ${numberOfMember}<span class="glyphicon glyphicon-user"></span></span>` }) messages.innerHTML = '' // 先移除旧的监听再绑定新的,避免重复回调 nsSocket.off('updateMessage') nsSocket.on('updateMessage', payload => { // 原有渲染逻辑不变 messages.innerHTML += ` <li> <div class="user-image"> <img src="https://via.placeholder.com/30" /> </div> <div class="user-message"> <div class="user-name-time">rbunch <span>${new Date(Date.now()).toDateString()}</span></div> <div class="message-text">${payload.data}</div> </div> </li> ` }) }
内容的提问来源于stack exchange,提问作者hamza
相关产品推荐
相关产品推荐

