我在Angular WebApp中使用socket.io
客户端。我把它包裹在一项服务中,但这可能不一定有意义。但是,由于传入的数据与使用该服务的控制器的范围不同,因此我始终必须调用$scope.$apply
。更糟糕的是,我发现了一些情况(在连接/重新连接期间),我必须使用safeApply
解释here。
我知道这是一个Angular Anti-Pattern,但是我没有办法解决这个问题。
是否有一般方法可以解决这个问题(最好是在服务内部),这种方法不会污染具有大量$scope.$apply/safeApply
的控制器?
BR, 丹尼尔
这里也是一些代码,有效,但并不好:
angular.module('mean')
.controller('ConnectionStateController', function ($scope) {
$scope.safeApply = function (fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if (fn && (typeof (fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
var socket = io.connect('http://localhost:3000');
$scope.message = 'Not connected';
socket.on('connect', function () {
$scope.safeApply(function () {
$scope.message = "Connected";
});
});
});
答案 0 :(得分:0)
在您的情况下,您知道socket.io
操作总是将异步运行并使其成为valid place to use $scope.$apply
(towards the bottom of the page)。
我建议不使用safeApply
并明确调用$scope.$apply
。使用safeApply
将掩盖实施中的真正错误。此外,如果要将代码包装在服务中,则可以在服务中注入$rootScope
并在$rootScope.$apply
中调用异步函数。然后,您无需在每个控制器中调用$scope.$apply
。
答案 1 :(得分:0)
我会自己回答这个问题,因为我有一个使用defer
的工作解决方案。不过我不确定我是否做得对。这是服务:
angular.module('mean')
.factory('ConnectionService', function ($q, $timeout) {
var bindings = {};
var socket = io.connect('http://localhost:3000');
// catch all events by overriding the socket's $emit
var $emit = socket.$emit;
socket.$emit = function (event, obj) {
console.log('***', 'on', '"' + event + '"', obj);
if (bindings.hasOwnProperty(event)) {
bindings[event].notify(obj);
}
$emit.apply(socket, arguments);
};
return {
socket: socket,
observe: function (event, callback) {
if (!bindings.hasOwnProperty(event)) {
bindings[event] = $q.defer();
}
bindings[event].promise.then(null, null, function (data) {
callback.apply(this, [ data ]);
});
}
};
});
这允许控制器使用如下服务:
ConnectionService.observe('news', function (data) {
$scope.message = data;
});
不确定,如果这是一个很好的解决方案,或者它有副作用,我还没有看到。
BR, 丹尼尔