2016-06-13 63 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