You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 21:54:04