2015-01-15 9 views
8

Ich habe zwei Direktiven, von denen jede dieselbe Factory verwendet und einen $ q/$ http-Aufruf einwickelt.AngularJS: Vermeiden Sie es, denselben REST-Service zweimal aufzurufen, bevor die Antwort empfangen wird

angular.module("demo").directive("itemA", ["restService", function(restService) { 
    return { 
     restrict: "A", 
     link: function(scope, element, attrs) { 
      restService.get().then(function(response) { 
       // whatever 
      }, function(response) { 
       // whatever 
      }); 
     } 
    }; 
}]); 


angular.module("demo").directive("itemB", ["restService", function(restService) { 
    return { 
     restrict: "A", 
     link: function(scope, element, attrs) { 
      restService.get().then(function(response) { 
       // whatever 
      }, function(response) { 
       // whatever 
      }); 
     } 
    }; 
}]); 

angular.module("demo").factory("restService", ["$http", "$q", function($http, $q) { 
    return { 
     get: function() { 
      var dfd = $q.defer(); 
      $http.get("whatever.json", { 
       cache: true 
      }).success(function(response) { 
       // do some stuff here 
       dfd.resolve(response); 
      }).error(function(response) { 
       // do some stuff here 
       dfd.reject(response); 
      }); 
     } 
    }; 
}]); 

Problem: Wenn ich dieses

<div item-a></div> 
<div item-b></div> 

bekomme ich die gleiche Web-Service zweimal abgefeuert, da der GET von Itema noch im Gange ist, wenn die GET für ItemB geht.

Gibt es eine Möglichkeit für das zweite Feuer zu wissen, dass es bereits eine Anfrage dazu gibt, so dass es eine Minute warten kann und es kostenlos holen kann?

Ich habe darüber nachgedacht, einen $ http oder $ q Wrapper zu erstellen, der jede URL als ausstehend kennzeichnet oder nicht, aber ich bin mir nicht sicher, ob das der beste Weg ist. Was würde ich tun, wenn es aussteht? Einfach das bestehende Versprechen zurückgeben und es wird aufgelöst, wenn der andere verrechnet wird?

+0

Vielleicht können Sie den Dienst einmal in Ihrem Controller aufrufen und das Objekt in beide Anweisungen übergeben? –

Antwort

17

Ja, alles, was Sie tun müssen, ist, das Versprechen zwischenzuspeichern und es nach der Anfrage zu säubern. Jede nachfolgende Anfrage kann das gleiche Versprechen verwenden.

angular.module("demo").factory("restService", ["$http", "$q", function($http, $q) { 
    var _cache; 
    return { 
     get: function() { 
      //If a call is already going on just return the same promise, else make the call and set the promise to _cache 
      return _cache || _cache = $http.get("whatever.json", { 
       cache: true 
      }).then(function(response) { 
       // do some stuff here 
       return response.data; 
      }).catch(function(response) { 
       return $q.reject(response.data); 
      }).finally(function(){ 
       _cache = null; //Just remove it here 
      }); 
     } 
    }; 
}]); 
+0

Das war sehr hilfreich. Nach einem langen Tag, denke ich, konnte ich einfach nicht daran denken, das Versprechen, das ich schon gemacht hatte, wiederzuverwerten. Ich habe es ein wenig modifiziert, weil wir im strikten Modus sind, aber es ist 90% was du hattest. – oooyaya

+0

@oooyaya cool. :) Fühlen Sie sich frei, meine Antwort zu aktualisieren, wenn Sie denken, dass es relevant ist. – PSL

+0

Nein, was Sie haben, ist in Ordnung. da war eine komische Sache. wir verwenden das deferred-Muster, so dass das. dann im Provider schließlich ein .then in der Direktive über resolve aufruft. Bei der Verwendung von .finally() wäre die Reihenfolge jedoch die des Providers, dann die des Providers, dann - zu der Zeit, als die Anweisung then() ging, wurde _dfd gelöscht und es explodierte. Also, wir haben gerade _dfd im Provider deaktiviert, aber nachdem wir es gelöst haben. Ich stelle mir vor, es gibt einen besseren Weg, aber das ist nur für einen POC. – oooyaya