2013-08-09 10 views
7

Thiết lập: Tôi muốn có một dịch vụ mà nhiều bộ điều khiển có thể truy vấn dữ liệu được kéo bằng cách sử dụng $ http. Giải pháp ban đầu là sử dụng lời hứa như đề xuất here.

Vấn đề: Mỗi lần bộ điều khiển truy vấn dịch vụ, dịch vụ sau đó trả về lời hứa $ http, dẫn đến nhiều truy vấn chỉ lấy cùng dữ liệu từ máy chủ từ xa.

Giải pháp: Chức năng dịch vụ trả về dữ liệu hoặc lời hứa như dưới đây. Và nó là để các bộ điều khiển để kiểm tra và hành động cho phù hợp.

app.factory('myService', function($http) { 
    var items = []; 
    var myService = { 
     getItems: function() { 
      // if items has content, return items; otherwise, return promise. 
      if (items.length > 0) { 
       return items; 
      } else {  
       var promise = $http.get('test.json').then(function (response) { 
        // fill up items with result, so next query just returns items. 
        for(var i=0;i<response.data.length;i++){ 
         items.push(response.data[i]); 
        } 
        return items; 
       }); 
       // Return the promise to the controller 
       return promise; 
      } 
    }; 
    return myService; 
}); 

Vì vậy, khi một bộ điều khiển cần dữ liệu, bộ điều khiển chỉ làm một cái gì đó như thế này:

app.controller('MainCtrl', function(myService,$scope) { 
    var promiseOrData = myService.async(); 
    // Check whether result is a promise or data. 
    if (typeof promiseOrData.then === 'function'){ 
     // It's a promise. Use then(). 
     promiseOrData.then(function(data){ 
      $scope.data = data; 
     }); 
    } else { 
     // It's data. 
     $scope.data = data; 
    } 
}); 

Vì vậy, câu hỏi là: Có cách nào tốt hơn để làm điều này? Với nhiều bộ điều khiển, phương pháp này sẽ có nhiều mã trùng lặp. Lý tưởng nhất, các bộ điều khiển sẽ chỉ truy vấn trực tiếp dịch vụ cho dữ liệu.

Cảm ơn!

Trả lời

12

$ http trả về lời hứa, chúng tôi có thể sử dụng thay vì tạo một cái mới với $ q. Khi lời hứa được giải quyết, chúng tôi có thể tiếp tục trả lời.

.factory('myService', ['$http','$q', function($http, $q) { 
    var items = []; 
    var last_request_failed = true; 
    var promise = undefined; 
    return { 
     getItems: function() { 
      if(!promise || last_request_failed) { 
       promise = $http.get('test.json').then(
       function(response) { 
        last_request_failed = false; 
        items = response.data; 
        return items; 
       },function(response) { // error 
        last_request_failed = true; 
        return $q.reject(response); 
       }); 
      } 
      return promise; 
     }, 
    }; 
}]) 

Trong điều khiển của bạn:

myService.getItems().then( 
    function(data) { $scope.data = data; } 
); 
+0

Thật tuyệt. Thậm chí tốt hơn nó làm giảm số lượng mã cần thiết trong bộ điều khiển. –

+0

Bất kỳ cách nào để làm cho DRY này nhiều hơn về phía dịch vụ? Tôi có một số điểm cuối http mà tôi muốn thực hiện việc này và lặp lại mã này cho mỗi dịch vụ/điểm cuối http sẽ bị loại khỏi tay –

+0

@KyleKochis, điều duy nhất tôi có thể làm là tạo một trình chặn HTTP duy nhất (http://stackoverflow.com/a/11957760/215945) để bắt lỗi HTTP cho tất cả các dịch vụ của tôi, vì vậy mã trên không còn cần xử lý lỗi nữa. –

1

Tạo lời hứa của riêng bạn để giải quyết dữ liệu được lưu trong bộ nhớ cache hoặc dữ liệu được tìm nạp.

app.factory('myService', function($http, $q) { 
    var items = []; 
    var myService = { 
     getItems: function() { 
      var deferred = $q.defer(); 

      if (items.length > 0) { 
       //resolve the promise with the cached items 
       deferred.resolve(items); 
      } else {  
       $http.get('test.json').then(function (response) { 
        // fill up items with result, so next query just returns items. 
        for(var i=0;i<response.data.length;i++){ 
         items.push(response.data[i]); 
        } 
        //resolve the promise with the items retrieved 
        deferred.resolve(items); 
       },function(response){ 
        //something went wrong reject the promise with a message 
        deferred.reject("Could not retrieve data!"); 
       }); 


      } 
     // Return the promise to the controller 
     return deferred.promise; 
    }; 
    return myService; 
}); 

Sau đó, sử dụng lời hứa trong bộ điều khiển của bạn.

app.controller('MainCtrl', function(myService,$scope) { 
    var promiseOrData = myService.getItems(); 

     promiseOrData.then(function(data){ 
      $scope.data = data; 
     }, 
     function(data){ 
      // should log "Could not retrieve data!" 
      console.log(data) 
     }); 

});