ProAngularJS Ch.20 Ajax 서비스 및 프로미스

#실행결과 http://study.jeju.onl/ch20/ajax.html

이장에서는 Ajax 기능을 활용하기 위한 $http와 프로미스 제어를 위한 $q에 대해서 설명하고 있다. 두 서비스는 Ajax의 비동기적 실행을 제어하기 위해 필수적인 기능이다. 이를 이용하여 REST 서비스를 구현할 수 있다.
주 내용은 다음과 같다.

  • Ajax 요청 수행
    – $http 의존성 선언, $http.get().success() 기능 정의
    – $http 메서드: get(), post(), delete(), put(), head(), jsonp()
    – Ajax 응답 수신: success(), error(), then( successFn(), errorFn() )
    – 응답정보 상세 조회: data, status, headers, config
  • Ajax 요청 설정
    – $http의 설정 속성: data, headers, method, params, timeout, transformRequest, transformResponse, withCredentials, xsrfHeaderNamesrf, CookieName
    – 응답 변형: transformResponse
    – 요청 변형: transformRequest
    – Ajax 기본값 설정: defaults 속성그룹
    – Ajax 인터셉터 활용: 요청 전과 응답 후에 기능 정의
    $httpProvider.interceptors
  • 프로미스 활용
    – $q 메서드: all(promises), defer(), reject(reason), when(value)
    – 지연객체 defer()의 메서드: resolve(result), reject(reason), notify(result), promise
    – 프로미스 처리: then( success, error, notify), catch(error), finally(fn)
    – 프로미스와 이벤트의 차이점
    1) 한번만 사용하고 버려짐. 프로미스는 단일 행동의 결과
    2) 활동의 실패 또는 미수행에 대해 이를 알려주는데 사용됨
    ==> Ajax 사용시 뭔가 잘못되었음을 알려주는 중요한 기능
    – 프로미스 체인: then( fn(result){ return result; })
    – 프로미스 그룹핑: 프로미스 배열을 선언후 $q.all()로 실행
    ==> 모든 입력 프로미스가 리졸브되어야 리졸부 됨 (AND)

이에 대한 소스코드이다.

<!DOCTYPE html>
<html ng-app="exampleApp">
<head>
  <title>DOM API Services - ProAngularJS</title>
  <link href="/node_modules/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
  <link href="/node_modules/bootstrap/dist/css/bootstrap-theme.css" rel="stylesheet" />

  /node_modules/angular/angular.js
  

  angular.module("exampleApp", [])
    .config( function( $httpProvider) {

      // $http의 모든 응답과 요청에 사용되는 기본 설정을 정의한다
      $httpProvider.defaults.transformResponse.push( function( data, headers) {
        if( headers("content-type").split('/')[1] == "xml" 
            && angular.isString(data)) {
          var products = [];
          var productElems = angular.element( data.trim()).find("product");
          for( var i=0; i 일회성(프로미스는 단일 행동의 결과이다)
            // cf. 이에 반해 click event는 횟수 정보 없이 여러번 사용 가능
            // 단 한번만 반드시 호출된다는 점에서 ajax 결과 알림에 매우 유용
            if( buttonText == "Abort") {
              //deferred.reject("Aborted");
              //console.log("deferred.reject('Aborted')");
              deferred[buttonGroup].reject("Aborted");
            } else {
              //deferred.resolve(buttonText);
              //console.log("deferred.resolve('"+buttonText+"')");
              deferred[buttonGroup].resolve(buttonText);
            }
          });
        },

        controller: function( $scope, $element, $attrs) {
          // 디렉티브의 콘트롤러에 promise 객체를 저장
          //this.promise = deferred.promise;
          // $q.all(): 모든 프로미스 이벤트가 만족되어야 실행된다
          this.promise = $q.all( promises).then( function( results) {
            return results.join();
          });
        }

      };

    })
    .directive( "promiseObserver", function() {

      return {
        require: "^promiseWorker",
        link: function( scope, element, attrs, ctrl) {
          // then 프로미스는 success, error, notify를 인자로 갖는다
          // 두번째 함수는 error시 호출됨
          // promise-worker에서 저장된 promise 객체를 통해 span 텍스트로 출력
          ctrl.promise.then( function( result) {
            return "2nd promise - Success ("+result+")";
          }, function( reason) {
            element.text("1st promise - Fail ("+reason+")");
          })
          .then( function(result) {
            // promise 체인에 의한 두번째 promise 호출
            element.text(result);
          });
        }
      };

    })
    .controller("defaultCtrl", function( $scope, $http, $q, $rootScope) {

      $scope.loadJsonData = function() {
        $http.get("productData.json")
          .success( function( data) {
            $scope.products = data;
          });
      };

      ///////////////////////

      $scope.loadXmlData = function() {
        /*
        $http.get("productData.xml")
          .success( function( data) {
            $scope.products = [];
            var productElems = angular.element( data.trim()).find("product");
            for( var i=0; i");
            for( var i=0; i");
              prodElem.attr("name", data[i].name);
              prodElem.attr("name", data[i].name);
              prodElem.attr("name", data[i].name);
              rootElem.append(prodElem)
            }
            rootElem.children().wrap("");
            return rootElem.html();
          }
        };

        $http.post("ajax.html", $scope.products, config);
      };

      function testDeferredAngularAsync() {
        var deferred = $q.defer();

        deferred.promise.then(function(result) {
          console.log('promise success');
        }, function(error) {
          console.log('promise error');
        });

        setTimeout(function() {
          console.log('resolving deferred');
          deferred.resolve();
          $rootScope.$apply();
        }, 1500);
      };

      // Works
      testDeferredAngularAsync();

    });

  
</head>
<body ng-controller="defaultCtrl">

  
NameCategoryPrice
No Data
{{ item.name }} {{ item.category }} {{ item.price | currency }}

Load JSON Load XML

Send XML

</div>
Heads Tails Abort
Yes No Abort
Outcome: <span promise-observer></span> </div> </body> </html>

 

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: