webentwicklung-frage-antwort-db.com.de

Können Sie ein eckiges Versprechen einlösen, bevor Sie es zurückgeben?

Ich versuche, eine Funktion zu schreiben, die ein Versprechen zurückgibt. Es gibt jedoch Situationen, in denen die angeforderten Informationen sofort verfügbar sind. Ich möchte es in ein Versprechen einwickeln, damit der Verbraucher keine Entscheidung treffen muss.

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        return $http.get('/someUrl', {id:id});
    }
}

Und benutze es so:

somethingService.getSomething(5).then(function(thing) {
    alert(thing);
});

Das Problem ist, dass der Rückruf für das vorab aufgelöste Versprechen nicht ausgeführt wird. Ist das eine legitime Sache? Gibt es eine bessere Möglichkeit, mit dieser Situation umzugehen?

121
Craig Celeste

Kurze Antwort: Ja, Sie können ein AngularJS-Versprechen lösen, bevor Sie es zurückgeben, und es verhält sich wie erwartet.

Von JB Nizets Plunkr aber überarbeitet, um im Kontext dessen zu arbeiten, was ursprünglich verlangt wurde (d. H. Ein Funktionsaufruf zum Service) und tatsächlich vor Ort.

Im Service ...

function getSomething(id) {
    // There will always be a promise so always declare it.
    var deferred = $q.defer();
    if (Cache[id]) {
        // Resolve the deferred $q object before returning the promise
        deferred.resolve(Cache[id]); 
        return deferred.promise;
    } 
    // else- not in cache 
    $http.get('/someUrl', {id:id}).success(function(data){
        // Store your data or what ever.... 
        // Then resolve
        deferred.resolve(data);               
    }).error(function(data, status, headers, config) {
        deferred.reject("Error: request returned status " + status); 
    });
    return deferred.promise;

}

In der Steuerung ....

somethingService.getSomething(5).then(    
    function(thing) {     // On success
        alert(thing);
    },
    function(message) {   // On failure
        alert(message);
    }
);

Ich hoffe es hilft jemandem. Ich fand die anderen Antworten nicht sehr klar.

172
h.coates

Wie man einfach ein vorab gelöstes Versprechen in Angular 1.x

Gelöstes Versprechen:

return $q.when( someValue );    // angular 1.2+
return $q.resolve( someValue ); // angular 1.4+, alias to `when` to match ES6

Abgelehntes Versprechen:

return $q.reject( someValue );

Hier ist, wie ich es normalerweise mache, wenn ich tatsächlich Daten in einem Array oder Objekt zwischenspeichern möchte

app.factory('DataService', function($q, $http) {
  var cache = {};
  var service= {       
    getData: function(id, callback) {
      var deffered = $q.defer();
      if (cache[id]) {         
        deffered.resolve(cache[id])
      } else {            
        $http.get('data.json').then(function(res) {
          cache[id] = res.data;              
          deffered.resolve(cache[id])
        })
      }
      return deffered.promise.then(callback)
    }
  }

  return service

})

DEMO

6
charlietfl

Ich benutze gerne eine Fabrik, um die Daten von meiner Ressource zu erhalten.

.factory("SweetFactory", [ "$http", "$q", "$resource", function( $http, $q, $resource ) {
    return $resource("/sweet/app", {}, {
        "put": {
            method: "PUT",
            isArray: false
        },"get": {
            method: "GET",
            isArray: false
        }
    });
}]);

Dann stellen Sie mein Modell hier im Service wie folgt aus

 .service("SweetService",  [ "$q", "$filter",  "$log", "SweetFactory",
    function ($q, $filter, $log, SweetFactory) {

        var service = this;

        //Object that may be exposed by a controller if desired update using get and put methods provided
        service.stuff={
            //all kinds of stuff
        };

        service.listOfStuff = [
            {value:"", text:"Please Select"},
            {value:"stuff", text:"stuff"}];

        service.getStuff = function () {

            var deferred = $q.defer();

          var promise = SweetFactory.get().$promise.then(
                function (response) {
                    if (response.response.result.code !== "COOL_BABY") {
                        deferred.reject(response);
                    } else {
                        deferred.resolve(response);
                        console.log("stuff is got", service.alerts);
                        return deferred.promise;
                    }

                }
            ).catch(
                function (error) {
                    deferred.reject(error);
                    console.log("failed to get stuff");
                }
            );

            promise.then(function(response){
                //...do some stuff to sett your stuff maybe fancy it up
                service.stuff.formattedStuff = $filter('stuffFormatter')(service.stuff);

            });


            return service.stuff;
        };


        service.putStuff = function () {
            console.log("putting stuff eh", service.stuff);

            //maybe do stuff to your stuff

            AlertsFactory.put(service.stuff).$promise.then(function (response) {
                console.log("yep yep", response.response.code);
                service.getStuff();
            }).catch(function (errorData) {
                alert("Failed to update stuff" + errorData.response.code);
            });

        };

    }]);

Dann können meine Controller es einbinden und es offenlegen oder tun, was es in seinem Kontext für richtig hält, indem sie einfach auf den injizierten Service verweisen

Scheint ok zu funktionieren. Aber ich bin ein bisschen neu in eckigen. * Fehlerbehandlung meist aus Gründen der Übersichtlichkeit weggelassen

0
Frank Swanson

Sie haben vergessen, das Cache-Element zu initialisieren

function getSomething(id) {
    if (Cache[id]) {
        var deferred = $q.defer();
        deferred.resolve(Cache[id]); // <-- Can I do this?
        return deferred.promise;
    } else {
        Cache[id] = $http.get('/someUrl', {id:id});
        return Cache[id];
    }
}
0
zs2020