Node.js + AngularJS + socket.io:连接状态并手动断开连接 [英] Node.js + AngularJS + socket.io: connect state and manually disconnect

查看:75
本文介绍了Node.js + AngularJS + socket.io:连接状态并手动断开连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在客户端上将nodejs与socket.io和angularjs一起使用.我从互联网上获取了angular-socketio示例,并向其中添加了disconnect方法.

I use nodejs with socket.io and angularjs on client. I picked up angular-socketio example from the Internet and added disconnect method to It.

套接字服务:

angular.module('app')
  .factory('socket', ['$rootScope', 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);
            }
          });
        })
      },
      disconnect: function () {
        socket.disconnect();
      },
      socket: socket
    };

  }]);

控制器:

angular.module('app')
  .controller('Controller', ['$scope', 'socket', function ($scope, socket) {

    socket.emit('register')

    socket.on('connect', function () {
        console.log('Socket connected');
    });

    socket.on('disconnect', function () {
        console.log('Socket disconnected');
    });

    socket.on('register', function (reginfo) {
        console.log('Register: %s, cname=%s', reginfo.ok, reginfo.cname);
        socket.disconnect(); // <-- this line throw Error
    });

    socket.on('last', updateSnapshot);

    socket.on('state', updateSnapshot);

    function updateSnapshot(snapshot) { ... }

}]);

但是当我尝试使用此方法断开连接时,出现错误:

But when I try to disconnect use this method I catch Error:

Error: $apply already in progress
  at Error (<anonymous>)
  at beginPhase (http://localhost:4000/scripts/vendor/angular.js:8182:15)
  at Object.$get.Scope.$apply (http://localhost:4000/scripts/vendor/angular.js:7984:11)
  at SocketNamespace.on (http://localhost:4000/scripts/services/socket.js:10:32)
  at SocketNamespace.EventEmitter.emit [as $emit] (http://localhost:4000/socket.io/socket.io.js:633:15)
  at Socket.publish (http://localhost:4000/socket.io/socket.io.js:1593:19)
  at Socket.onDisconnect (http://localhost:4000/socket.io/socket.io.js:1970:14)
  at Socket.disconnect (http://localhost:4000/socket.io/socket.io.js:1836:12)
  at SocketNamespace.<anonymous> (http://localhost:4000/scripts/controllers/controller.js:38:34)
  at on (http://localhost:4000/scripts/services/socket.js:11:34)

我不知道在哪里挖……

推荐答案

[更新]

$$phase是Angular的内部私有变量,因此您不应该真正依赖于此.伊戈尔在另一个答案中描述了一些处理此问题的建议,应该改用一些建议(我听说他对Angular知道一两件事.)

$$phase is an internal, private variable to Angular, and thus you should not really depend on it for things like this. Igor describes, in another answer, some suggestions for handling this which should be used instead (I hear he knows a thing or two about Angular. ;)

当模型更改并且事件从Angular框架内触发时,Angular可以根据需要进行脏跟踪并更新任何必要的视图.当您想与Angular的代码 outside 进行交互时,您必须将必要的函数调用包装在作用域的$apply方法中,以便Angular知道正在发生的事情.这就是代码读取的原因

When models change and events fire from within the Angular framework, Angular can do dirty tracking as necessary and update any necessary views. When you want to interact with code outside of Angular, you have to wrap the necessary function calls in the $apply method of a scope, so that Angular knows something is happening. That's why the code reads

$rootScope.$apply(function () {
  callback.apply(socket, args);
});

,依此类推.它告诉Angular,采用通常不会触发Angular视图更新的代码,并按应有的方式对待它."

and so forth. It's telling Angular, "take this code that normally wouldn't trigger Angular view updates, and treat it like it should."

问题是当您已经在$apply呼叫中时调用$apply时.例如,以下内容将引发$apply already in progress错误:

The problem is when you call $apply when you're already in an $apply call. For example, the following would throw an $apply already in progress error:

$rootScope.$apply(function() {
  $rootScope.$apply(function() {
    // some stuff
  });
});

根据您的堆栈跟踪,看起来对emit(已经使用$apply的某些调用)触发了对on(也使用$apply的)调用.要解决此问题,仅在$apply尚未进行时才需要调用$apply.值得庆幸的是,作用域上有一个名为$$phase的属性,它可以告诉我们是否正在进行脏检查.

Based on your stack trace, it looks like some call to emit (which already uses $apply) triggered a call to on (which also uses $apply). To fix this problem, we need to only call $apply if an $apply is not already in progress. Thankfully, there is a property on the scope called $$phase that can tell us if a dirty check is in progress.

我们可以轻松地构建一个带有作用域和要运行的函数的函数,然后仅当尚未运行该函数时才使用$apply运行该函数:

We can easily build a function that takes a scope and a function to run, and then runs the function with $apply only if one isn't already in progress:

var safeApply = function(scope, fn) {
  if (scope.$$phase) {
    fn(); // digest already in progress, just run the function
  } else {
    scope.$apply(fn); // no digest in progress, run the function with $apply
  }
};

现在我们可以替换对的呼叫

Now we can replace calls to

$rootScope.$apply(function...);

safeApply($rootScope, function...);

例如,要修改上面的代码,

For example, to modify the code you have above,

angular.module('app')
  .factory('socket', ['$rootScope', function ($rootScope) {

    var safeApply = function(scope, fn) {
      if (scope.$$phase) {
        fn(); // digest already in progress, just run the function
      } else {
        scope.$apply(fn); // no digest in progress, run with $apply
      }
    };

    var socket = io.connect();

    return {
      on: function (eventName, callback) {
        socket.on(eventName, function () {  
          var args = arguments;
          safeApply($rootScope, function () {
            callback.apply(socket, args);
          });
        });
      },
      emit: function (eventName, data, callback) {
        socket.emit(eventName, data, function () {
          var args = arguments;
          safeApply($rootScope, function () {
            if (callback) {
              callback.apply(socket, args);
            }
          });
        })
      },
      disconnect: function () {
        socket.disconnect();
      },
      socket: socket
    };

  }]);

这篇关于Node.js + AngularJS + socket.io:连接状态并手动断开连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆