반환하기 전에 angularjs 약속을 해결할 수 있습니까?


125

약속을 반환하는 함수를 작성하려고합니다. 그러나 요청 된 정보를 즉시 사용할 수있는 경우가 있습니다. 소비자가 결정을 내릴 필요가 없도록 약속으로 포장하고 싶습니다.

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});
    }
}

다음과 같이 사용하십시오.

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

문제는 콜백이 미리 해결 된 약속에 대해 실행되지 않는다는 것입니다. 이것이 합법적 인 일입니까? 이 상황을 처리하는 더 좋은 방법이 있습니까?


10
첫 번째 경우에 수익을 작성하는 더 간단한 방법은 return $q.when(Cache[id]). 어쨌든 이것은 매번 새로운 약속을 생성하기 때문에 매번 작동하고 콜백을 호출해야합니다.
musically_ut


1
Crud. 내 인생의 한 시간을 잃었습니다. 나는 이것을 단위 테스트에서 시도하고 있었고 테스트가 완료된 후에 약속이 성취되었지만 나는 그것을 보지 못했습니다. 코드가 아닌 내 테스트에 문제가 있습니다.
Craig Celeste

$ scope. $ apply ()를 호출하여 테스트 중에 문제가 즉시 해결되는지 확인하십시오.
dtabuenc

나는 httpbackend.flush가 이것을 고려한다고 생각하지만 $ q는 그렇지 않을 수도 있습니다. 이 테스트에서는 범위를 사용하지 않습니다. 서비스를 직접 테스트하고 있지만 어쨌든 작동하게되었습니다. 감사합니다.
Craig Celeste

답변:


174

짧은 답변 : 예, 반환하기 전에 AngularJS 약속을 해결할 수 있으며 예상대로 작동합니다.

에서 JB Nizet의 Plunkr 하지만 원래 요청이 있었는지의 맥락 내에서 작동하도록 리팩토링 (서비스 즉, 함수 호출) 실제로 사이트.

서비스 내부 ...

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;

}

컨트롤러 내부 ....

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

누군가에게 도움이되기를 바랍니다. 다른 답변은 명확하지 않았습니다.


2
얼마나 기뻤는지 말로 표현할 수 없어요. h.coates!
rilar 2014-04-02

http GET이 실패하는 경우 반환 된 promise는 이러한 방식으로 거부되지 않습니다.
lex82

5
따라서이 게시물의 tl; dr은 다음과 같습니다. 예, 약속을 반환하기 전에 약속을 해결할 수 있으며 의도 한대로 단락됩니다.
ray

1
이 답변은 Angular의 약속이 기반으로하는 Kris Kowal의 Q에도 적용됩니다.
Keith

귀하의 답변에 오류 처리 예제를 추가했지만 괜찮기를 바랍니다.
Simon East

98

Angular 1.x에서 미리 해결 된 프라 미스를 간단히 반환하는 방법

해결 된 약속 :

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

거부 된 약속 :

return $q.reject( someValue );

1
해당 공장이 필요하지 않습니다. 이러한 도우미 기능은 이미 사용 가능합니다.{resolved: $q.when, rejected: $q.reject}
Bergi

안녕 Bergi, 귀중한 의견에 감사드립니다. 그에 따라 내 대답을 편집했습니다.
Andrey Mikhaylov-lolmaus 2015

2
이 답변을 선택해야한다고 생각합니다.
Morteza Tourani 2016 년

@mortezaT 선택되면 황금 배지를 얻지 못할 것입니다. ;)
Andrey Mikhaylov-lolmaus

6

실제로 배열 또는 객체의 데이터를 캐시하려는 경우 일반적으로 수행하는 방법은 다음과 같습니다.

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


0

캐시 요소를 초기화하는 것을 잊었습니다.

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];
    }
}

죄송합니다. 사실입니다. 질문의 명확성을 위해 코드를 단순화하려고했습니다. 그럼에도 불구하고 미리 해결 된 promise에 들어가면 콜백을 호출하지 않는 것 같습니다.
Craig Celeste

2
약속으로 약속을 해결하면 내면의 약속이 평평해질 것이라고 생각하지 않습니다. 이것은 Cache의도 된 객체 대신 약속으로 채울 것이고 객체가 캐시에있을 때와 그것이 동일하지 않을 때의 반환 유형이 될 것입니다. 이보다 정확, 내 생각 :$http.get('/someUrl', {id: id}).then(function (response) { Cache[id] = response.data; return Cache[id]; });
musically_ut

0

나는 공장을 사용하여 내 리소스에서 데이터를 얻는 것을 좋아합니다.

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

그런 다음 여기와 같은 서비스에서 내 모델을 노출하십시오.

 .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);
            });

        };

    }]);

그런 다음 내 컨트롤러는 삽입 된 서비스를 참조하여이를 포함하고 노출하거나 컨텍스트에서 올바른 작업을 수행 할 수 있습니다.

잘 작동하는 것 같습니다. 하지만 저는 각도에 익숙하지 않습니다. * 명확성을 위해 대부분 생략 된 오류 처리


귀하의 getStuff방법은 사용하고 연기 안티 패턴을
BERGI
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.