我在客户端上将nodejs与socket.io和angularjs一起使用。我从互联网上获取了angular-
socketio示例,并向其中添加了disconnect
方法。
套接字服务:
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) { ... }
}]);
但是,当我尝试使用此方法断开连接时,出现错误:
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知道一两件事。)
当模型发生变化并且事件从Angular框架内触发时,Angular可以根据需要进行脏跟踪并更新任何必要的视图。当您想与Angular 之外
的代码进行交互时,您必须将必要的函数调用包装在$apply
作用域的方法中,以便Angular知道正在发生的事情。这就是代码读取的原因
$rootScope.$apply(function () {
callback.apply(socket, args);
});
等等。它告诉Angular,“采用通常不会触发Angular视图更新的代码,并按应有的方式对待它。”
问题是当您$apply
已经在通话中时$apply
拨打电话。例如,以下内容将引发$apply already in progress
错误:
$rootScope.$apply(function() {
$rootScope.$apply(function() {
// some stuff
});
});
根据您的堆栈跟踪,看起来某些调用emit
(已经使用$apply
)触发了调用on
(也使用$apply
)。为了解决这个问题,我们只需要调用$apply
如果$apply
不是已在进行中。值得庆幸的是,作用域上有一个属性$$phase
,可以告诉我们是否正在进行脏检查。
我们可以轻松地构建一个需要作用域和功能才能运行的功能,然后$apply
仅在尚未运行该功能的情况下运行该功能:
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
}
};
现在我们可以替换对
$rootScope.$apply(function...);
至
safeApply($rootScope, function...);
例如,要修改上面的代码,
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
};
}]);
问题内容: 我使用和创建一个实时Web应用程序。我将为用户提供对套接字连接的完全控制,例如手动断开连接和(重新)连接。 在客户端启动时,该功能可以正常运行,但是在使用之后,不会启动新连接。 问题答案: 现在可以使用socket.socket.reconnect() 相关:https : //github.com/LearnBoost/socket.io- client/issues/251
问题内容: 我正在使用node.js和socket.io构建一个小型原型。一切运行正常,我面临的唯一问题是我的node.js连接将断开连接,并且我被迫刷新页面以重新建立连接并重新运行。 有一种方法可以在断开事件触发后立即重新建立连接? 据我所知,这是一个普遍的问题。因此,我正在寻找解决该问题的最佳实践方法:) 非常感谢,丹 问题答案: 编辑:Socket.io已内置支持现在 当我使用socket.
当用户关闭选项卡或重新加载页面时,disconnect事件应该会触发,但当通过Nginx和CloudFlare传递连接时,则不会触发。提前感谢您的帮助! 更新:似乎在重新加载/关闭断开连接事件后的几秒钟内最终注册。
问题内容: 我正在使用Socket.io,并且想知道从客户端到服务器的连接状态。 像这样: 如果连接断开或由于任何原因断开连接,我需要此信息来向用户提供视觉反馈。 问题答案: 您可以检查属性: 它是动态更新的,如果连接丢失,它将设置为,直到客户端再次选择连接为止。很容易检查或类似的东西。 另一个解决方案是捕获事件并自己跟踪状态。
问题内容: 我有一个使用服务器上的nodejs和socket.io作为连接机制的客户端/服务器应用程序。出于与我的应用程序相关的原因,我希望每个浏览器只有一个活动连接,并拒绝来自其他选项卡的所有连接,这些选项卡可能在会话期间稍后打开。这在WebSockets上很好用,但是如果浏览器不支持WebSockets,而是使用XHR- polling,则断开连接永远不会发生,因此,如果用户只是刷新页面,则不
断开mqtt连接,前提是必须已经通过Iot_id,Iot_pwd建立过一次mqtt连接。 请求方式: "|4|1|4|\r" 返回值: "|4|1|4|1|\r" 断开成功 "|4|1|4|2|\r" 断开失败 Arduino样例: softSerial.print("|4|1|4|\r");