在角色服务/控制器中实施安全$申请的最佳方法

时间:2013-12-09 08:29:13

标签: javascript angularjs socket.io

我在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";
            });
        });
    });

2 个答案:

答案 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, 丹尼尔

相关问题