javascript - UI-Router 的 Angular Service 异步单例

标签 javascript angularjs asynchronous angular-ui-router

我正在使用UI-Router对于 Angular 应用程序。我有通过 $http 异步调用提取的数据,该调用用于创建某种连接对象。我的目标是有某种方法来创建这个对象并使其作为单例可用。尽管发生这种情况的可能性很小,但我希望避免异步分配服务中的 socket 属性的计时问题。当路由器中的不同状态想要获取或创建另一个连接对象时,它将通过单例来实现,以便可以使用相同的连接而不是创建另一个连接。

下面是我试图开始工作的一些代码的框架。我不确定是否可以通过状态的 resolve 来完成某些操作。

关于如何做到这一点有什么想法或建议吗?

var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', function($http) {
    var socket;

    // Somehow call and store result of $http in a singleton
    // Would the $http.get get put in some kind of function? If so, how should it get called 
    // and returned so that a user of the service can get the 'socket' object synchronously?
        $http.get("something/that/returns/data")
            .success(function (result) {
                this.socket= createConnection(result.data);
            })
            .error(function (err) {
                //handle error
            })

    var getSocket= function() {
        if (!this.socket) {
            return createNewSocket();
        } else {
            return this.socket;
        }
    }
}])

myapp.config(function($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("home");

    $stateProvider
        .state('home', {
            url: "/home",
            templateUrl: "home.html",
            resolve: {
                socket: // ??? Can something be done here ???
            },
            controller: function(socket) {
                // I can haz socket?
            }
        })
        .state('nextState', {
            url: "/next",
            templateUrl: "next.html",
            resolve: {
                socket: // Should be the same socket object as from the home state
            },
            controller: function(socket) {
                // I can haz same socket?
            }
        })
})
<小时/>

更新

在尝试更好地解释问题的过程中,我对原始代码进行了几次更改。人们留下的评论纠正了我所犯的明确错误。我已将上面的代码恢复为原来的样子,并在下面添加了新的代码。我仍然遇到的问题是,在进入 Controller 之前,ui-router 状态上的 resolve 并未解析。因此,当在应该解析的 socket 对象上调用 emit() 时,出现“无法读取未定义的属性‘emit’”的错误。我还仍然希望 socket 对象在状态之间是相同的对象。如果有任何其他建议或评论能够引导我走向正确的方向,我将不胜感激。

var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', function($http) {
    var socket;

    // Somehow call and store result of $http in a singleton
    // Would the $http.get get put in some kind of function? If so, how should it get called 
    // and returned so that a user of the service can get the 'socket' object synchronously?
    $http.get("something/that/returns/data")
        .then(function (result) {
            socket = createConnection(result.data);
        }, function (err) {
            // handle error
        });

    var getSocket = function() {
        if (!socket) {
            // handle error
        } else {
            return socket;
        }
    }
}])

myapp.config(function($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("home");

    $stateProvider
        .state('home', {
            url: "/home",
            templateUrl: "home.html",
            resolve: {
                socket: function(connectionService) {
                    return connectionService.getSocket();
                }
            },
            controller: function(socket) {
                socket.emit("some msg");
            }
        })
        .state('nextState', {
            url: "/next",
            templateUrl: "next.html",
            resolve: {
                socket: function(connectionService) {
                    return connectionService.getSocket();
                }
            },
            controller: function(socket) {
                socket.emit("some other msg");
            }
        })
})
<小时/>

更新2

工作解决方案,但这并不像Muli Yulzari那么优雅的答案已被接受为正确答案。

我考虑创建自己的 promise 并将其作为 ui-router 解决的问题返回。根据我所有的调试和堆栈跟踪,状态之间只创建了一个连接,并且进入 Controller 的操作被推迟,直到连接解决为止。所以,我相信这是一个有效的解决方案。我还有一个代码版本,可以在解决 promise 之前处理连接上的 onConnect 事件,但为了简洁起见,我将其省略了。

var myapp = angular.module('me', ['ui.router'])
.service('connectionService', ['$http', '$q', function($http, $q) {
    var socket;

    this.getSocket = function() {
        if (!socket) {
            var deferred = $q.defer();

            $http.get("something/that/returns/data")
                .then(function (result) {
                    socket = createConnection(result.data);
                    deferred.resolve(socket);
                }, function (err) {
                    // handle error
                    deferred.reject(socket);
                });

            return deferred.promise;
        } else {
            return socket;
        }
    }
}])

myapp.config(function($stateProvider, $urlRouterProvider) {
    $urlRouterProvider.otherwise("home");

    $stateProvider
        .state('home', {
            url: "/home",
            templateUrl: "home.html",
            resolve: {
                socket: function(connectionService) {
                    return connectionService.getSocket();
                }
            },
            controller: function(socket) {
                socket.emit("some msg");
            }
        })
        .state('nextState', {
            url: "/next",
            templateUrl: "next.html",
            resolve: {
                socket: function(connectionService) {
                    return connectionService.getSocket();
                }
            },
            controller: function(socket) {
                socket.emit("some other msg");
            }
        })
})

最佳答案

据我了解,每次套接字实例无效时,您都希望根据来自 $http.get 的数据初始化套接字,但在应用程序加载时异步执行此操作。

.service('connectionService', ['$http', '$q', function($http, $q) {
    //For caching the socket
    var socket;

    //Do the first get
    tryGetData();

    //tryGetData executes $http.get and returns a promise that when fulfilled -
    //returns the new socket instance.
    function tryGetData(){
     return $http.get("something/that/returns/data")
        .then(function (result) {
            return socket = createConnection(result.data);
        }, function (err) {
            // handle error
        });
    }

    //Whenever getSocket gets called, it first checks if the socket is instantiated. if not -
    //assumes the $http.get failed and tries again to instantiate the socket calling
    //$http.get again in the process.
    //this function returns a promise for controllers to rely on.
    this.getSocket = function(){
     if(socket) return $q.resolve(socket);
     return tryGetData();
    }
}]);

其余代码看起来不错。

关于javascript - UI-Router 的 Angular Service 异步单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37798461/

相关文章:

asynchronous - 我可以将 async 和 wait 与 Tornado-redis 一起使用吗? (Python 3.5)

c# - EF中这两个异步调用有什么区别?

postgresql - .NETCore PostgreSQL "A command is already in progress"

日历

javascript - Javascript getter/setter 的奇怪行为

javascript - 输入动态填充时 AngularJS 表单验证失败

javascript - 如果使用 js 在我的网站上没有图像,如何设置手动默认图像?

javascript - AOL9.0并不断发送AJAX请求

javascript - OMDb API 无法在 JavaScript 中运行

javascript - Protractor ,失败 : unknown error: cannot focus element on custom input field