wake-up-neo.com

Zwischenspeichern eines Versprechungsobjekts im AngularJS-Dienst

Ich möchte ein dynamisches Laden einer statischen Ressource in AngularJS mithilfe von Promises implementieren. Das Problem: Ich habe einige Komponenten auf der Seite, die möglicherweise (oder nicht abhängig davon, welche angezeigt werden, also dynamisch) eine statische Ressource vom Server benötigen. Nach dem Laden kann es für die gesamte Anwendungslebensdauer zwischengespeichert werden.

Ich habe diesen Mechanismus implementiert, aber ich bin neu in Angular und Promises, und ich möchte sicherstellen, dass dies eine richtige Lösung ist.

var data = null;
var deferredLoadData = null;

function loadDataPromise() {
  if (deferredLoadData !== null)
    return deferredLoadData.promise;

  deferredLoadData = $q.defer();

  $http.get("data.json").then(function (res) {
    data = res.data;
    return deferredLoadData.resolve();
  }, function (res) {
    return deferredLoadData.reject();
  });

  return deferredLoadData.promise;
}

Es wird also nur eine Anforderung gestellt, und alle nächsten Aufrufe von loadDataPromise () erhalten das erste gemachte Versprechen zurück. Es scheint für die Anfrage zu funktionieren, dass der Fortschritt bereits vor einiger Zeit abgeschlossen wurde.

Aber ist es eine gute Lösung, um Versprechen zwischenzuspeichern?

34
andrew.fox

Ist das der richtige Ansatz?

Ja. Die Verwendung von memoization on-Funktionen, die zurückkehren, verspricht eine übliche Technik, um die wiederholte Ausführung von asynchronen (und in der Regel teuren) Aufgaben zu vermeiden. Das Versprechen macht die Zwischenspeicherung einfach, da nicht zwischen laufenden und abgeschlossenen Vorgängen unterschieden werden muss. Beide werden als (dasselbe) Versprechen für den Ergebniswert dargestellt.

Ist das die richtige Lösung?

Nein. Diese globale Variable data und die Auflösung mit undefined ist nicht so, wie Versprechen funktionieren sollen. Erfüllen Sie stattdessen das Versprechen mit dem Ergebnis data! Es erleichtert auch die Codierung:

var dataPromise = null;

function getData() {
    if (dataPromise == null)
        dataPromise = $http.get("data.json").then(function (res) {
           return res.data;
        });
    return dataPromise;
}

Anstelle von loadDataPromise().then(function() { /* use global */ data }) ist es dann einfach getData().then(function(data) { … }).

Um das Muster weiter zu verbessern, möchten Sie möglicherweise dataPromise in einem Schließungsbereich ausblenden und feststellen, dass Sie nach verschiedenen Versprechungen suchen müssen, wenn getData einen Parameter (wie die URL) verwendet.

47
Bergi

Für diese Aufgabe habe ich einen Dienst namens defer-cache-service erstellt, der den gesamten Code der Speicherplatte entfernt. Es wurde in TypeScript geschrieben, Sie können jedoch eine kompilierte JS-Datei abrufen. Github Quellcode .

Beispiel:

function loadCached() {
   return deferCacheService.getDeferred('cacke.key1', function () {
      return $http.get("data.json");
   }); 
} 

und verbrauchen

loadCached().then(function(data) {
//...
});

Es ist wichtig zu wissen, dass wenn zwei oder mehr Teile das gleiche loadDataPromise aufrufen und gleichzeitig aufgerufen werden, diese Prüfung hinzugefügt werden muss

if (defer && defer.promise.$$state.status === 0) {
   return defer.promise;
}

andernfalls führen Sie doppelte Aufrufe für das Backend durch.

3

Dieses Entwurfsmuster wird cache was immer zurückgegeben wird, wenn es zum ersten Mal ausgeführt wird, und gibt das cached - Ding zurück, wenn es erneut aufgerufen wird.

const asyncTask = (cache => {
  return function(){
    // when called first time, put the promise in the "cache" variable
    if( !cache ){
        cache = new Promise(function(resolve, reject){
            setTimeout(() => {
                resolve('foo');
            }, 2000);
        });
    }
    return cache;
  }
})();

asyncTask().then(console.log);
asyncTask().then(console.log);

Erläuterung:

Umschließen Sie Ihre Funktion einfach mit einer anderen selbstaufrufenden Funktion, die eine Funktion zurückgibt (Ihre ursprüngliche async-Funktion). Der Zweck der Wrapper-Funktion besteht darin, den Gültigkeitsbereich für die lokale Variable cache bereitzustellen, sodass die lokale Variable nur innerhalb der zurückgegebenen Funktion von verfügbar ist die Wrapper-Funktion und hat bei jedem Aufruf von asyncTask den gleichen Wert (anders als beim allerersten Mal)

0
vsync