【问题标题】:socket.on event gets triggered multiple timessocket.on 事件被多次触发
【发布时间】:2018-09-22 03:02:40
【问题描述】:
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 次提出问题,那么 listeners 数组将有 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;
  }
 });
}

【问题讨论】:

  • 目前尚不清楚您要实现的设计究竟是什么,所以我真的不明白问题是什么,或者您期望正确的行为是什么。您的代码似乎还使用了一些共享变量,例如 replyFromBotlisten,它们将在多个用户的请求之间共享,并且可能会导致问题。但是,我在此特定代码中看不到任何会导致重复事件处理程序的问题。客户端是否存在重复的处理程序?
  • replyFromBot 和 listen 只是在另一个函数中使用的东西,它们不会引起任何问题,请忽略它们。
  • 我想要实现的是用户将问题发送到服务器问题就像“data = Hi 你能帮我解决这个问题吗”,socket.emit('Quest', data); bot.reply 将搜索问题的适当答案,并以 socket.emit('Ans' , replyFromBot); 的形式回复客户端;
  • 所以如果第一次问问题,那么我会得到一个答复,但是如果我第二次问它,我会得到相同的答复 2 次第三个问题会得到 3 个答复,依此类推
  • 您在此处显示的服务器代码不会导致该问题。对于'Quest' 消息,每个套接字只有一个且只有一个服务器事件处理程序,并且每次收到传入消息时都发送一个'Ans' 响应。我看不到您显示的代码如何导致您描述的问题,除非问题是在客户端引起的。也许我们需要查看客户端代码。

标签: node.js express socket.io


【解决方案1】:

代替socket.on('Quest' ,reply); 试试socket.once('Quest' ,reply);

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

socket.once() 确保绑定到已注册事件“Quest”的套接字的事件侦听器数量正好是一个

【讨论】:

  • socket.once 只会调用一次,我的意思是它适用于第一次和第二次客户提出的问题 socket.once 不会执行我试过这个它不会工作。我想在其中工作就像一个循环,因为客户会再次提问。谢谢思考
  • 在我看来这不是问题。 connection 事件在每个连接中只发生一次,因此每个套接字的'Quest' 消息只有一个事件处理程序。
【解决方案2】:

问题是由您的客户端代码引起的。每次在客户端调用 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,因为一旦您有多个用户使用您的服务器,这些都是等待发生的并发问题。


更好的解决方案

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

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;
    });
}

这样做,您可以直接从消息中回复,因此它作为请求/响应的方式比您之前的方式要好得多。

【讨论】:

  • 我添加了一个代码示例,用于使用ack 功能,socket.io 必须从消息中获得直接响应。
  • 感谢 ack 代码,这也正是我想要的。是的,我意识到那些共享变量会对此进行调查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-07
  • 1970-01-01
相关资源
最近更新 更多