2016-06-13 64 views
1

我正在使用UI-Router作为Angular应用程序。我有通过用于创建排序连接对象的异步调用$http来获取数据。我的目标是创建这个对象并将其作为单例提供。虽然发生这种情况的可能性很少,但我期望避免在服务的socket属性异步分配时发生时间问题。当路由器中的另一个状态想要获取或创建另一个连接对象时,它将通过单例执行此操作,以便可以使用相同的连接而不是创建另一个连接。角度服务异步单身UI-Router

下面是一些代码的框架,我试图去工作。我不确定是否可以用国家的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? 
      } 
     }) 
}) 

更新

在试图更好地解释这个问题的过程中,我已经改变了原来的代码几次。人们留下的评论改正了我的错误。我已经将上面的代码恢复到了原来的样子,并在下面添加了新的代码。我仍然存在的问题是在进入控制器之前,ui-router状态下的resolve未被解析。因此,在socket对象上调用emit()时,我认为“Can not read property”的错误会导致“undefined”。我还希望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的答案。

我研究了创建自己的承诺并将其作为ui-router解决的问题返回。根据我的所有调试和堆栈跟踪,在这些状态之间只有一个连接被创建,并且进入控制器的时间被延迟直到连接被解决。所以,我相信这是一个可行的解决方案。在解决承诺之前,我还有一个处理连接事件的代码版本,但为了简洁起见,我已将其忽略。

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"); 
      } 
     }) 
}) 
+0

在角度上,服务是单身,所以这确实是你想要的。但是,您的服务构建方式存在一些问题;具体而言,在回调中使用'.this'将不会按照您的意图工作,因为'.this'指的是回调,而不是父服务。另外,你应该考虑切换到'.then'而不是弃用的'.success'。 – Claies

+0

删除不推荐的'.success'并切换到'。然后'承诺。 – BoJoe22

+1

你仍然在承诺中使用'.this',这是不起作用的主要部分。 – Claies

回答

0

据我了解,你要根据来自$http.get每次数据初始化插座Socket实例是无效的,但这样做的同时,异步应用程序加载。

.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(); 
    } 
}]); 

其余的代码看起来不错。

+0

这很接近,但tryGetData()没有返回ui-router的解析可以处理的承诺。我有一个解决方案,用于创建$ q延迟对象并返回该延迟对象的承诺。我会发布该解决方案,但希望能够为您提供帮助。 – BoJoe22

+0

它的确如此。检查这个链接:https://docs.angularjs.org/api/ng/service/$http#get –

+0

是的,'$ http'确实返回一个承诺。但是在这里写的方式,'tryGetData()'不会返回这个promise,因为'.then()'已经被调用。不知道如何用适当的术语来解释它。另外,在返回promise结果之前,我需要一种方法来处理从'$ http.get'返回的数据。因此,我需要抓住'$ http'的承诺并重新推出另一个。至少这是我的观察。我可能是完全错误的... – BoJoe22