AngularJS에서 Promise와 함께 success / error / finally / catch 사용


112

내가 사용하고 $httpAngularJS와에, 나는 반환 약속을 사용하는 방법과 핸들 오류를 모르겠어요.

이 코드가 있습니다.

$http
    .get(url)
    .success(function(data) {
        // Handle data
    })
    .error(function(data, status) {
        // Handle HTTP error
    })
    .finally(function() {
        // Execute logic independent of success/error
    })
    .catch(function(error) {
        // Catch and handle exceptions from success/error/finally functions
    });

이것이 좋은 방법입니까, 아니면 더 쉬운 방법이 있습니까?

답변:


103

약속은 우리가 비동기 코드로 자신을 동 기적으로 표현할 수있게 해주는 문에 대한 추상화입니다. 일회성 작업의 실행을 나타냅니다.

또한 일반 코드와 마찬가지로 예외 처리를 제공하므로 약속에서 반환하거나 던질 수 있습니다.

동기 코드에서 원하는 것은 다음과 같습니다.

try{
  try{
      var res = $http.getSync("url");
      res = someProcessingOf(res);
  } catch (e) {
      console.log("Got an error!",e);
      throw e; // rethrow to not marked as handled
  }
  // do more stuff with res
} catch (e){
     // handle errors in processing or in error.
}

약속 된 버전은 매우 유사합니다.

$http.get("url").
then(someProcessingOf).
catch(function(e){
   console.log("got an error in initial processing",e);
   throw e; // rethrow to not marked as handled, 
            // in $q it's better to `return $q.reject(e)` here
}).then(function(res){
    // do more stuff
}).catch(function(e){
    // handle errors in processing or in error.
});

4
, 어떻게 사용 success()하고 error()finally()결합 catch()하시겠습니까? 아니면 사용해야합니까then(successFunction, errorFunction).catch(exceotionHandling).then(cleanUp);
Joel

3
@Joel은 일반적으로 successand error(선호 .then하고 .catch대신 위의 코드에서와 같이 사용 ac errorFunction에서 생략 할 수 있습니다 (그리고 생략해야 함) ). .thencatch
Benjamin Gruenbaum 2014 년

@BenjaminGruenbaum success/ 피하라고 제안하는 이유를 자세히 설명해 주 error시겠습니까? 또한 내 Eclipse는을 볼 때 amok 실행 .catch(되므로 지금은 사용 ["catch"](합니다. Eclipse를 어떻게 길들일 수 있습니까?
Giszmo

Angular의 $ q 라이브러리의 $ http 모듈 구현은 .then 및 .catch 대신 .success 및 .error를 사용합니다. 그러나 내 테스트에서 .then 및 .catch 약속을 사용할 때 $ http 약속의 모든 속성에 액세스 할 수 있습니다. 또한 zd333의 답변을 참조하십시오.
Steve K

3
@SirBenBenji $ Q이없는 .success.error, $ HTTP는 $ q를 약속 반환 추가와 함께successerror핸들러 - 그러나,이 핸들러 체인을하지 일반적 경우 / 가능하면 피해야한다. 일반적으로-질문이있는 경우 이전 질문에 대한 의견이 아닌 새로운 질문으로 질문하는 것이 가장 좋습니다.
Benjamin Gruenbaum 2015-06-02

43

사용법 successerror방법 은 잊어 버리십시오 .

두 방법 모두 angular 1.4에서 더 이상 사용되지 않습니다. 기본적으로 지원 중단의 이유는 말하자면 체인에 친화적 이지 않기 때문 입니다.

다음의 예를 통해, 나는에 대해 무엇을 의미하는지 설명하려고합니다 successerror되지 인 체인 방식 친화적 인 . 주소와 함께 사용자 객체를 반환하는 API를 호출한다고 가정합니다.

사용자 개체 :

{name: 'Igor', address: 'San Francisco'}

API를 호출합니다.

$http.get('/user')
    .success(function (user) {
        return user.address;   <---  
    })                            |  // you might expect that 'obj' is equal to the
    .then(function (obj) {   ------  // address of the user, but it is NOT

        console.log(obj); // -> {name: 'Igor', address: 'San Francisco'}
    });
};

어떻게 된 거예요?

때문에 successerror반환 원래의 약속 , 즉에 의해 반환되는 한 $http.get,의 콜백에 전달 된 개체가 then전체 인 사용자 이전에 동일한 입력 말을하는 것입니다 객체, success콜백.

두 개를 연결했다면 then덜 혼동되었을 것입니다.

$http.get('/user')
    .then(function (user) {
        return user.address;  
    })
    .then(function (obj) {  
        console.log(obj); // -> 'San Francisco'
    });
};

1
또한 가치가 있음을 지적 success하고 error있다 에만 즉시 반환에 추가$http당신이 그 (와 같은, 당신은 일반적으로 호출 사이에 다른 약속 메서드를 호출 할 경우 그래서, 전화 (안 프로토 타입) return $http.get(url)기본 라이브러리에 싸여,하지만 나중에 결정에 스피너를 전환 )를 사용하여 라이브러리를 호출 return $http.get(url).finally(...)하면 더 이상 편리한 메서드를 사용할 수 없습니다.
drzaus 2015

35

이전 답변이 정확하다고 생각하지만 여기에 또 다른 예가 있습니다 (Fyi, success () 및 error () 만 AngularJS Main page 에 따라 더 이상 사용되지 않습니다 .

$http
    .get('http://someendpoint/maybe/returns/JSON')
    .then(function(response) {
        return response.data;
    }).catch(function(e) {
        console.log('Error: ', e);
        throw e;
    }).finally(function() {
        console.log('This finally block');
    });

3
마지막으로 내가 아는 한 응답을 반환하지 않습니다.
diplosaurus 2015 년

11

어떤 유형의 세분성을 찾고 있습니까? 일반적으로 다음을 통해 얻을 수 있습니다.

$http.get(url).then(
  //success function
  function(results) {
    //do something w/results.data
  },
  //error function
  function(err) {
    //handle error
  }
);

여러 약속을 연결할 때 "finally"와 "catch"가 더 낫다는 것을 알았습니다.


1
귀하의 예에서 오류 처리기는 $ http 오류 만 처리합니다.
Benjamin Gruenbaum

1
예, 성공 / 오류 기능에서도 예외를 처리해야합니다. 그리고 나는 (내가 좋아하는 일을 설정할 수있는 일반적인 처리기의 일종 필요 loading = false)
조엘

1
then () 호출을 닫는 괄호 대신 중괄호가 있습니다.
Paul McClean 2015

1
404 응답 오류에 대한이 나던 일 만에 작동 .catch()방법
elporfirio

이 컨트롤러에 반환 된 HTTP 오류를 처리하기위한 정답
레온

5

Angular $ http의 경우 success () 및 error () 함수는 응답 객체가 풀리므로 콜백 서명은 $ http (...). success (function (data, status, headers, config))와 같습니다.

then ()의 경우 원시 응답 객체를 다룰 것입니다. AngularJS $ http API 문서에 게시 된 것과 같은

$http({
        url: $scope.url,
        method: $scope.method,
        cache: $templateCache
    })
    .success(function(data, status) {
        $scope.status = status;
        $scope.data = data;
    })
    .error(function(data, status) {
        $scope.data = data || 'Request failed';
        $scope.status = status;
    });

마지막 .catch (...)는 이전 promise 체인에서 새로운 오류가 발생하지 않는 한 필요하지 않습니다.


2
성공 / 오류 메소드는 더 이상 사용되지 않습니다.
OverMars

-3

나는 Bradley Braithwaite가 그의 블로그 에서 제안한 것처럼 그것을합니다 .

app
    .factory('searchService', ['$q', '$http', function($q, $http) {
        var service = {};

        service.search = function search(query) {
            // We make use of Angular's $q library to create the deferred instance
            var deferred = $q.defer();

            $http
                .get('http://localhost/v1?=q' + query)
                .success(function(data) {
                    // The promise is resolved once the HTTP call is successful.
                    deferred.resolve(data);
                })
                .error(function(reason) {
                    // The promise is rejected if there is an error with the HTTP call.
                    deferred.reject(reason);
                });

            // The promise is returned to the caller
            return deferred.promise;
        };

        return service;
    }])
    .controller('SearchController', ['$scope', 'searchService', function($scope, searchService) {
        // The search service returns a promise API
        searchService
            .search($scope.query)
            .then(function(data) {
                // This is set when the promise is resolved.
                $scope.results = data;
            })
            .catch(function(reason) {
                // This is set in the event of an error.
                $scope.error = 'There has been an error: ' + reason;
            });
    }])

키 포인트:

  • resolve 함수는 컨트롤러의 .then 함수에 연결됩니다. 즉 모든 것이 정상이므로 약속을 지키고 해결할 수 있습니다.

  • reject 함수는 컨트롤러의 .catch 함수에 연결됩니다. 즉, 무언가 잘못되었으므로 약속을 지킬 수없고 거부해야합니다.

매우 안정적이고 안전하며 약속을 거부 할 다른 조건이있는 경우 언제든지 성공 함수에서 데이터를 필터링 deferred.reject(anotherReason)하고 거부 이유를 호출 할 수 있습니다 .

Ryan Vice가 의견에서 제안했듯이 답변을 조금만 조작하지 않으면 유용하지 않을 수 있습니다.

때문에 success그리고 error1.4부터 사용되지 않습니다 어쩌면 정규 약속 방법을 사용하는 것이 좋습니다 thencatch그 방법 내에서 응답을 변환하고 변환 응답의 약속을 반환합니다.

두 가지 접근 방식과 세 번째 중간 접근 방식으로 동일한 예를 보여줍니다.

successerror접근 ( success그리고 errorHTTP 응답 $q의 약속을 반환하므로 데이터 약속을 반환하는 데 도움이 필요합니다 ) :

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)
  .success(function(data,status) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(data);              
  })

  .error(function(reason,status) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.error){
      deferred.reject({text:reason.error, status:status});
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({text:'whatever', status:500});
    }
  });

  // The promise is returned to the caller
  return deferred.promise;
};

then그리고 catch접근 (이것은 던지기 때문에 테스트하기가 조금 더 어렵습니다) :

function search(query) {

  var promise=$http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    return response.data;
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      throw reason;
    }else{
      //if we don't get any answers the proxy/api will probably be down
      throw {statusText:'Call error', status:500};
    }

  });

  return promise;
}

그래도 중간 해결책이 있습니다 (이렇게하면 피할 수 throw있고 어쨌든 $q테스트에서 promise 동작을 모의하는 데 사용해야 할 것입니다 ).

function search(query) {
  // We make use of Angular's $q library to create the deferred instance
  var deferred = $q.defer();

  $http.get('http://localhost/v1?=q' + query)

  .then(function (response) {
    // The promise is resolved once the HTTP call is successful.
    deferred.resolve(response.data);
  },function(reason) {
    // The promise is rejected if there is an error with the HTTP call.
    if(reason.statusText){
      deferred.reject(reason);
    }else{
      //if we don't get any answers the proxy/api will probably be down
      deferred.reject({statusText:'Call error', status:500});
    }

  });

  // The promise is returned to the caller
  return deferred.promise;
}

어떤 종류의 의견이나 수정도 환영합니다.


2
Promise에서 Promise를 랩핑하기 위해 $ q를 사용하는 이유는 무엇입니까? $ http.get ()에 의해 반환 된 promise를 반환하지 않는 이유는 무엇입니까?
Ryan Vice

때문에 success()error()같은 새로운 약속을 반환하지 않을 then()않습니다. 함께 $q우리 대신 HTTP 응답의 약속의 데이터의 약속을 반환하는 우리의 공장을합니다.
Watchmaker

당신의 반응이 혼란스러워서 제가 잘 설명하지 못하는 것 같습니다. 응답을 조작하지 않는 한 $ http가 반환하는 약속을 간단히 반환 할 수 있습니다. : 난 그냥 쓴이 예를 참조 jsbin.com/belagan/edit?html,js,output
라이언 부통령

1
가치가 보이지 않습니다. 나에게는 불필요하다고 느끼고이 접근 방식을 사용하는 내 프로젝트에 대한 코드 검토를 거부하지만 가치를 얻는다면 사용해야합니다. 또한 불필요한 포장을 냄새로 부르는 각도 모범 사례 기사에서 몇 가지 약속을 보았습니다.
Ryan Vice

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.