Joswlv

AngularJS_Promise객체 와 $q서비스

2016-07-08
js

Promise객체

promise 객체는 약속을 표현하는 자바스크립트 객체이다.

AngularJS에서 $http,$tiemoute,$resource,$route등 여러 서비스에서 promise객체를 반환한다.

function fetchData(id, cb){
  getDataFromServer(id, function(err, result){
    if(err){
      cb(err, null);
    }else{
      transformData(result, function(err, transformedResult){
        if(err){
          cb(err, null);
        }else{
          saveToIndexDB(result, function(err, savedData){
            cb(err, savedData);
          });
        }
      });
    }
  });
}

위 코드는 콜백지옥이다. promise객체를 사용하면 다음과 같다.

function fetchData(id){
  return getDataFromServer(id)
          .then(transformData)
          .then(saveToIndexDB);
}

then으로 묶어 주면 된다. 코드가 예뻐졌다. 그리고 error처리도 쉬워진다.

fetchData(1)
  .then(function(result){

  }, function(error){
    // exceptions in transformData, or saveToIndexDB
    // will result in this error callback being called.
  });

Deferred객체

약속을 정의했으면 누군가는 약속을 지키거나 거절해야 한다. 이러한 일을 하는 것이 deferred객체이다. deferred객체는 약속을 만들고 만든 약속의 상태를 변경한다.

AngluarJS는 $q.deferred()를 이용하여 deferred객체를 생성할 수 있다. (deferred객체 생성은 곧 Promise객체 생성이기도 하다.)

deferred객체는 resolve,reject,notify를 통하여 약속으 지키거나 거절/취소하여 진행 상태를 알려준다.

deferred객체는 주로 별도의 서비스를 만들고 해당 서비스에서 생성하여 해당 객체의 약속을 반환하는 식으로 많이 사용된다.

angular.module('demo-app', [])
  .factory('userService', function($http, $log, $q) {
    return {
     getUser: function(userId) {
       //deferred 객체를 생성한다.
       var deferred = $q.defer();
       $http.get('/api/users/' + userID)
         .success(function(data) {
            //요청이 성공하면 약속을 지키고 별도 데이터를 전달한다.
            deferred.resolve({
               name: data.name,
               address: data.address});
         }).error(function(msg, code) {
            //요청이 실패하면 약속을 취소하고 메시지를 전달한다.
            deferred.reject(msg);
            $log.error(msg, code);
         });
       //해당 deferred 객체의 약속을 반환한다.
       return deferred.promise;
     }
    }
	});

여러 Promise 묶어주기($q.all)

$q 서비스는 미래에 지켜지거나 지켜지지 않을 여러 약속을 하나의 약속으로 처리할 수 있는 API도 제공한다.

factory('asyncService', function($http, $q) {
  return {
    loadDataFromTwoReq: function() {
      var deferred = $q.defer(),
          httpPromise1 = $http.get('/api/req1'),
          httpPromise2 = $http.get('/api/req2');

      //두 약속을 $q.all 메서드를 이용해 새로운 약속을 만든다.
      $q.all(httpPromise1, httpPromise2)
        .then(
          function(results) {
            //두 약속이 모두 지켜지면 asyncService서비스가 반한하는 약속을 지키고 두 약속이 전달하는 결과를 묶은 배열로 전달한다.
            deferred.resolve(results)
          },
          function(errors) {
            deferred.reject(errors);
          },
          function(updates) {
          deferred.update(updates);
        });
      return deferred.promise;
    }
  };
});

위 코드는 일반적인 콜백 방식으로 작성하게 되면 첫 번째 요청의 성공 콜백에서 다른 요청을 하고 그 요청의 성공 콜백에서 두 요청에 대한 성공 처리를 하는 코드를 작성하게 된다.

하지만!! $q 서비스는 $q.all 메서드를 이용해 약속을 바환하는 여러 비동기적인 일이 병렬적으로 행해지고 있다. 약속을 하나로 묶어 성공/실패 처리를 할 수 있게 해준다.

References


Comments