首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >socket.on事件多次被触发

socket.on事件多次被触发
EN

Stack Overflow用户
提问于 2018-04-12 05:09:07
回答 2查看 8.2K关注 0票数 5
代码语言:javascript
运行
复制
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+9+8....+1侦听器,那么它将继续增加,这取决于客户机询问的问题的数量。这不太好

我试着使用removeListener,它只删除了一次侦听器,并且第二次进行了多次调用。你们有什么建议?我是这样做的,还是有其他方法在socket.on调用时添加侦听器,在执行时删除侦听器,下次调用时再添加侦听器

谢谢你。

客户代码:

代码语言:javascript
运行
复制
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;
  }
 });
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-04-12 06:05:13

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

代码语言:javascript
运行
复制
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并不是真正作为请求/响应系统构建的,这正是您试图将其用作的。实现这一点的一个更好的方法是使用 capability that socket.io has,这样您就可以直接响应您发送的Quest消息。

您还需要修复服务器上的共享变量replyFromBotlisten,因为一旦有多个用户使用您的服务器,这些都是等待发生的并发问题。

更好解决方案

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

代码语言:javascript
运行
复制
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);
    });
}

然后,将客户端代码更改为:

代码语言:javascript
运行
复制
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;
    });
}

这样做,您就可以从消息中直接链接到一个回复,因此它作为请求/响应的工作方式要比您所使用的方式要好得多。

票数 16
EN

Stack Overflow用户

发布于 2018-04-12 05:33:18

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

代码中的错误是,每次调用newConnection()节点时,都会注册一个事件侦听器'Quest‘。因此,当第一次调用newConnection()时,带有事件“Quest”的事件侦听器数量为1,第二次调用函数,事件侦听器数量增至2,依此类推。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49788422

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档