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调用时添加侦听器,在执行时删除侦听器,下次调用时再添加侦听器
谢谢你。
客户代码:
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;
}
});
}
发布于 2018-04-12 06:05:13
问题是由您的客户端代码引起的。每次在客户端调用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并不是真正作为请求/响应系统构建的,这正是您试图将其用作的。实现这一点的一个更好的方法是使用 capability that socket.io has,这样您就可以直接响应您发送的Quest
消息。
您还需要修复服务器上的共享变量replyFromBot
和listen
,因为一旦有多个用户使用您的服务器,这些都是等待发生的并发问题。
更好解决方案
更好的解决方案是使用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;
});
}
这样做,您就可以从消息中直接链接到一个回复,因此它作为请求/响应的工作方式要比您所使用的方式要好得多。
发布于 2018-04-12 05:33:18
而不是socket.on('Quest' ,reply);
,尝试socket.once('Quest' ,reply);
代码中的错误是,每次调用newConnection()
节点时,都会注册一个事件侦听器'Quest‘。因此,当第一次调用newConnection()
时,带有事件“Quest”的事件侦听器数量为1,第二次调用函数,事件侦听器数量增至2,依此类推。
socket.once()
确保与已注册的事件'Quest‘绑定到套接字的事件侦听器数量恰好是一个
https://stackoverflow.com/questions/49788422
复制相似问题