【问题标题】:Socket.io - Event listener firing twiceSocket.io - 事件监听器触发两次
【发布时间】:2015-11-22 12:54:40
【问题描述】:

我正在使用 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;

【问题讨论】:

    标签: javascript node.js sockets


    【解决方案1】:

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

    使用EventEmitter.removeAllListeners()

    您不需要使用此方法的函数引用。该事件的所有侦听器都将被删除。如果没问题,这是最简单的解决方案。

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

    保留对监听器的引用

    如果您不想删除所有侦听器,则必须保留对处理函数的引用。在原型方法上调用.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));
    };
    

    【讨论】:

      【解决方案2】:

      试试这个:

      /**
       * 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() {
          var self = this;
          this.socket.on('player.move', function(position){
            self.move(position);
          });
          this.socket.on('player.logout', function() {
            self.__unbind();
          });
      };
      
      /**
       * Remove event listeners
       * @private
       */
      Player.prototype.__unbind = function() {
          this.socket.on('player.move', function(position) {
            console.log('[!] Cannot move to position ['+positon[0]+','+position[1]+']. Reason: loged out');
          });
      };
      
      // Exports
      module.exports = Player;
      

      【讨论】:

      • 请用文字解释您所做的更改以及解决问题的原因。
      • 首先我改变了你使用闭包绑定事件的方式,其次我创建了“self”变量以避免与“this”发生冲突,第三我让用户重写事件处理程序空的关闭而不是删除它。
      • 请将此解释添加到您的实际答案中。
      猜你喜欢
      • 2017-01-08
      • 1970-01-01
      • 1970-01-01
      • 2021-10-29
      • 2017-12-03
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多