改进此AngularJS工厂以与socket.io一起使用

Gal*_*aim 52 socket.io angularjs

我想在AngularJS中使用socket.io.我找到了以下工厂:

app.factory('socket', function ($rootScope) {
    var socket = io.connect();
    return {
        on: function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        },
        emit: function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            })
        }
    };
Run Code Online (Sandbox Code Playgroud)

它在控制器中使用如:

function MyCtrl($scope, socket) {
    socket.on('message', function(data) {
        ...
    });
};
Run Code Online (Sandbox Code Playgroud)

问题是每次访问控制器时都会添加另一个侦听器,因此在收到消息时会多次处理.

什么是将socket.io与AngularJS集成的更好策略?

编辑:我知道我可以在工厂中没有返回任何内容并在那里进行监听,然后在控制器中使用$ rootScope.$ broadcast和$ scope.$ on,但它看起来不是一个好的解决方案.

EDIT2:加入工厂

init: function() {
            socket.removeAllListeners();
}
Run Code Online (Sandbox Code Playgroud)

并在每个使用socket.io的控制器的开头调用它.

仍然不觉得最好的解决方案.

bml*_*ite 52

每当控制器被销毁时删除套接字侦听器.您需要绑定$destroy事件,如下所示:

function MyCtrl($scope, socket) {
    socket.on('message', function(data) {
        ...
    });

    $scope.$on('$destroy', function (event) {
        socket.removeAllListeners();
        // or something like
        // socket.removeListener(this);
    });
};
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看angularjs文档.


Mic*_*ley 8

您可以通过包装Scope并观察$destroy要进行广播来完成最少量的工作来处理这个问题,当它只是从套接字中删除在该Scope的上下文中添加的侦听器时.请注意:以下内容尚未经过测试 - 我认为它更像伪代码而不是实际代码.:)

// A ScopedSocket is an object that provides `on` and `emit` methods,
// but keeps track of all listeners it registers on the socket.
// A call to `removeAllListeners` will remove all listeners on the
// socket that were created via this particular instance of ScopedSocket.

var ScopedSocket = function(socket, $rootScope) {
  this.socket = socket;
  this.$rootScope = $rootScope;
  this.listeners = [];
};

ScopedSocket.prototype.removeAllListeners = function() {
  // Remove each of the stored listeners
  for(var i = 0; i < this.listeners.length; i++) {
    var details = this.listeners[i];
    this.socket.removeListener(details.event, details.fn);
  };
};

ScopedSocket.prototype.on = function(event, callback) {
  var socket = this.socket;
  var $rootScope = this.$rootScope;

  var wrappedCallback = function() {
    var args = arguments;
    $rootScope.$apply(function() {
      callback.apply(socket, args);
    });
  };

  // Store the event name and callback so we can remove it later
  this.listeners.push({event: event, fn: wrappedCallback});

  socket.on(event, wrappedCallback);
};

ScopedSocket.prototype.emit = function(event, data, callback) {
  var socket = this.socket;
  var $rootScope = this.$rootScope;

  socket.emit(event, data, function() {
    var args = arguments;
    $rootScope.$apply(function() {
      if (callback) {
        callback.apply(socket, args);
      }
    });
  });
};

app.factory('Socket', function($rootScope) {
  var socket = io.connect();

  // When injected into controllers, etc., Socket is a function
  // that takes a Scope and returns a ScopedSocket wrapping the
  // global Socket.IO `socket` object. When the scope is destroyed,
  // it will call `removeAllListeners` on that ScopedSocket.
  return function(scope) {
    var scopedSocket = new ScopedSocket(socket, $rootScope);
    scope.$on('$destroy', function() {
      scopedSocket.removeAllListeners();
    });
    return scopedSocket;
  };
});

function MyController($scope, Socket) {
  var socket = Socket($scope);

  socket.on('message', function(data) {
     ...
  });
};
Run Code Online (Sandbox Code Playgroud)


mar*_*eli 5

我会对接受的答案添加评论,但我不能.所以,我会写一个回复.我遇到了同样的问题,我发现的最容易和最简单的答案就是你可以在这里找到的那个,在michaeljoser提供的另一篇文章中.

为方便起见,我会在下面复制它:

您必须将removeAllListeners添加到工厂(见下文)并在每个控制器中包含以下代码:

$scope.$on('$destroy', function (event) {
socket.removeAllListeners();
});
Run Code Online (Sandbox Code Playgroud)

更新套接字工厂:

var socket = io.connect('url');
    return {
        on: function (eventName, callback) {
            socket.on(eventName, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    callback.apply(socket, args);
                });
            });
        },
        emit: function (eventName, data, callback) {
            socket.emit(eventName, data, function () {
                var args = arguments;
                $rootScope.$apply(function () {
                    if (callback) {
                        callback.apply(socket, args);
                    }
                });
            })
        },
      removeAllListeners: function (eventName, callback) {
          socket.removeAllListeners(eventName, function() {
              var args = arguments;
              $rootScope.$apply(function () {
                callback.apply(socket, args);
              });
          }); 
      }
    };
});
Run Code Online (Sandbox Code Playgroud)

它节省了我的一天,我希望它对别人有用!