1. 程式人生 > >在AngularJS中使用$q同步讀取伺服器資料

在AngularJS中使用$q同步讀取伺服器資料


今天在寫AngularJS Service,然後希望在Controller中使用Service提供Model。架構上,我希望Controller可以直接獲得資料,因此有了“同步讀取”資料的想法。

但是,我們都知道,在前端做同步讀取顯然不是好的實踐做法,畢竟JavaScript的很多良好體驗都是通過非同步請求實現的。而且,同步之後會嚴重影響前端的體驗和效能。所以,這裡把標題寫成“同步讀取伺服器資料”,更多是吸引眼球。希望剛剛你不是拿著磚頭正準備拍的!:)

不過,我在網上搜索了一下,還真有人一開始和我想法一樣的,見參考資料2。轉入正題。

AngularJS提供了一個內建Service $q,它提供了一種承諾/延後(promise/deferred),可以保證我們的呼叫程式碼一定能夠拿到資料。當然,我們可以猜到,最後去伺服器取資料的方式肯定是非同步的。只不過這個服務提供了表面上是同步訪問的API,當資料獲取成功之後,自動將資料提供給呼叫的程式碼。

$q – A promise/deferred implementation inspired by Kris Kowal’s Q.

The CommonJS Promise proposal describes a promise as an interface for interacting with an object that represents the result of an action that is performed asynchronously, and may or may not be finished at any given point in time.

話不多說,上程式碼看看:

1. 建立一個Service,去伺服器讀取資料:

// $q 是內建服務,所以可以直接使用
ngApp.factory('UserInfo', ['$http', '$q', function ($http, $q) {
  return {
    query : function() {
      var deferred = $q.defer(); // 宣告延後執行,表示要去監控後面的執行
      $http({method: 'GET', url: 'scripts/mine.json'}).
      success(function(data, status, headers, config) {
        deferred.resolve(data);  // 宣告執行成功,即http請求資料成功,可以返回資料了
      }).
      error(function(data, status, headers, config) {
        deferred.reject(data);   // 宣告執行失敗,即伺服器返回錯誤
      });
      return deferred.promise;   // 返回承諾,這裡並不是最終資料,而是訪問最終資料的API
    } // end query
  };
}]);

2. 在Controller上(以同步方式)使用這個Service:
angular.module('ngApp')
  .controller('MainCtrl', ['$scope', 'UserInfo', function ($scope, UserInfo) { // 引用我們定義的UserInfo服務
    var promise = UserInfo.query(); // 同步呼叫,獲得承諾介面
    promise.then(function(data) {  // 呼叫承諾API獲取資料 .resolve
        $scope.user = data;
    }, function(data) {  // 處理錯誤 .reject
        $scope.user = {error: '使用者不存在!'};
    });
  }]);

歡迎討論和交流AngularJS及前端開發。

參考資料: