gpt4 book ai didi

javascript - Socket.io - 事件监听器触发两次

转载 作者:行者123 更新时间:2023-11-28 19:02:31 24 4
gpt4 key购买 nike

我正在使用 Socket.io 在 NodeJS 中编写游戏。我有一个 Player 类,用户可以在其中登录和退出游戏。但是,当客户端注销游戏并重新加入其旧事件监听器时,会触发两次。

我尝试查看this问题,但它似乎不起作用,因为它仍然产生重复的输出。

我的代码:

输出:

[+] Player [OZYaW0Ncrfg21NJDAAAB] has logged in.
[+] Player moved to [10,111]
[-] Player [OZYaW0Ncrfg21NJDAAAB] has logged out.
[+] Player moved to [10,111]
[+] Player [OZYaW0Ncrfg21NJDAAAB] has logged in.
[+] Player moved to [10,111]
[+] Player moved to [10,111] <-- this should not happen!
[-] Player [OZYaW0Ncrfg21NJDAAAB] has logged out.

client.js

var socket = io('http://localhost:8080/');
socket.emit('player.login');
socket.emit('player.move', [10, 111]);
socket.emit('player.logout');
socket.emit('player.move', [10, 111]);
socket.emit('player.login');
socket.emit('player.move', [10, 111]);
socket.emit('player.logout');

ma​​in.js

var io = require('socket.io')(8080);
var Player = require('./Player');

// All players
var players = {};

io.on('connection', function(socket) {

// On login
socket.on('player.login', function() {
players[socket.id] = new Player(socket);
console.log('[+] Player [' + socket.id + '] has logged in.');
});

// On logout
socket.on('player.logout', function() {
delete players[socket.id];
console.log('[-] Player [' + socket.id + '] has logged out.');
});
});

Player.js

/**
* Player class
* @param socket
* @constructor
*/
function Player(socket) {
this.socket = socket;
this.position = {x : 0, y : 0};
this.__bind();
}

/**
* Move a player
* @param {Array} position
*/
Player.prototype.move = function(position) {
this.position.x = position[0];
this.position.y = position[1];
console.log("[+] Player moved to [" + position[0] + ',' + position[1] + ']');
};

/**
* Add event listeners
* @private
*/
Player.prototype.__bind = function() {
this.socket.on('player.move', this.move.bind(this));
this.socket.on('player.logout', this.__unbind.bind(this));
};

/**
* Remove event listeners
* @private
*/
Player.prototype.__unbind = function() {
this.socket.removeListener('player.move', this.move);
};

// Exports
module.exports = Player;

最佳答案

问题是 EventEmitter.removeListener()需要对监听器函数的引用。您传递了 this.move,但实际的监听器函数是 this.move.bind(this)。您没有保留对该函数的引用,因此无法使用 removeListener() 删除监听器。您有几个选择:

使用EventEmitter.removeAllListeners()

此方法不需要函数引用。该事件的所有监听器都将被删除。如果可以的话,这是最简单的解决方案。

Player.prototype.__unbind = function() {
this.socket.removeAllListeners('player.move');
};

保留对监听器的引用

如果您不想删除所有监听器,则必须保留对处理函数的引用。在构造函数中分配一个属性,该属性在原型(prototype)方法上调用 .bind(this)

function Player(socket) {
this.socket = socket;
this.position = {x : 0, y : 0};
this.move = this.__move.bind(this)
this.__bind();
}

Player.prototype.__move = function(position) {
this.position.x = position[0];
this.position.y = position[1];
console.log("[+] Player moved to [" + position[0] + ',' + position[1] + ']');
};

Player.prototype.__bind = function() {
this.socket.on('player.move', this.move); // already bound!
this.socket.on('player.logout', this.__unbind.bind(this));
};

关于javascript - Socket.io - 事件监听器触发两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32261269/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com