socket.on事件被多次触发

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了socket.on事件被多次触发相关的知识,希望对你有一定的参考价值。

var express = require('express');
var app = express();
var server = app.listen(3000);
var replyFromBot;
app.use(express.static('public'));
var socket = require('socket.io');
var io = socket(server);
io.sockets.on('connection' , newConnection);

function newConnection(socket) {
   console.log(socket.id);
   listen = true;
   socket.on('Quest' ,reply);
   function reply(data) {
     replyFromBot = bot.reply("local-user", data);
     console.log(socket.id+ " "+replyFromBot);
     socket.emit('Ans' , replyFromBot);
  }
}

我使用node.js socket.io和express创建了一个基于服务器的聊天机器人应用程序,但这是第一次当我调用socket.on它被执行一次,第二次它被执行两次第三次三次所以我通过在我的客户端上设置一个标志来解决这个问题,这样它只会显示一次。我只是想知道我的代码在逻辑上是否正确我的意思是这是一个很好的代码?因为如果客户问第10次问题,那么听众阵列将会有10 + 9 + 8 ...... + 1个听众,这将继续增加,具体取决于客户提出的问题数量。这不好

我尝试使用removeListener它只删除一次侦听器,并且第二次调用它。你们推荐什么?我是这样做的还是有任何其他方法在socket.on调用时添加监听器并在执行时删除它并再次添加监听器以便下次调用它

谢谢。

客户代码:

function reply() {
  socket.emit('Quest' , Quest);
  flag = true;
  audio.play();
  socket.on('Ans', function(replyFromBot) {
  if(flag) {
    console.log("hi");
    var para = document.createElement("p2");
    x = document.getElementById("MiddleBox");
    para.appendChild(document.createTextNode(replyFromBot));
    x.appendChild(para);
    x.scrollTop = x.scrollHeight;
    flag = false;
  }
 });
}
答案

问题是由您的客户端代码引起的。每次在客户端调用reply()函数时,都会设置一个额外的socket.on('Ans', ...)事件处理程序,这意味着它们会累积。您可以将其更改为socket.once(),每次获取Ans消息后它将自行删除。然后,您还可以删除flag变量。

function reply() {
  socket.emit('Quest' , Quest);
  audio.play();
  // change this to .once()
  socket.once('Ans', function(replyFromBot) {
    console.log("hi");
    var para = document.createElement("p2");
    x = document.getElementById("MiddleBox");
    para.appendChild(document.createTextNode(replyFromBot));
    x.appendChild(para);
    x.scrollTop = x.scrollHeight;
  });
}

Socket.io并不是真正构建为请求/响应系统,而是您尝试将其用作。实现这一点的更好方法是使用ack capability that socket.io has,这样您就可以直接回复您发送的Quest消息。

您还需要在服务器上修复共享变量replyFromBotlisten,因为只要有多个用户使用您的服务器,就会出现并发问题。


改善方案

更好的解决方案是使用socket.io必须直接响应您发送的消息的ack功能。为此,您需要将服务器更改为:

function newConnection(socket) {
    console.log(socket.id);
    socket.on('Quest', function(data, fn) {
      let replyFromBot = bot.reply("local-user", data);
      console.log(socket.id+ " "+replyFromBot);
      // send ack response
      fn(replyFromBot);
    });
}

并将您的客户端代码更改为:

function reply() {
    audio.play();
    socket.emit('Quest', Quest, function(replyFromBot) {
        console.log("hi");
        var para = document.createElement("p2");
        x = document.getElementById("MiddleBox");
        para.appendChild(document.createTextNode(replyFromBot));
        x.appendChild(para);
        x.scrollTop = x.scrollHeight;
    });
}

这样做,你就可以直接回复消息,因此它的请求/响应比你的方式更好。

另一答案

而不是socket.on('Quest' ,reply);尝试socket.once('Quest' ,reply);

代码中的错误是每次调用newConnection()节点时都会注册一个事件监听器'Quest'。所以第一次调用newConnection()事件监听器的数量与事件'Quest'是一,第二次调用函数,事件监听器的数量增加到两个,依此类推

socket.once()确保绑定到套接字的事件监听器的数量与注册的事件'Quest'正好相同

以上是关于socket.on事件被多次触发的主要内容,如果未能解决你的问题,请参考以下文章

如何在前端获取 socket.on 函数?事件被触发和处理。我正在使用 socket.io、NodeJS 服务器和 Redis.io

Socket.io 事件多次发出

Socket.io-防止触发多个事件

socket.io 连接事件未在 Firefox 中触发

RxJava 作为事件总线被多次调用,即使只触发一次

为啥 jQuery 选择事件侦听器会触发多次?