본문 바로가기
  • 오늘도 한걸음. 수고많았어요.^^
  • 조금씩 꾸준히 오래 가자.ㅎ
IT기술/javascript

자바스크립트 Promise

by 미노드 2021. 2. 6.

Promise란 어떤 것인가?

주로 서버에서 데이터를 불러오고 화면에 표시할 때 사용한다.
3가지 처리 상태를 이용하여 불러오는 상황에 맞춰 원하는 결과를 표시 할 수 있다.
데이터를 불러오기 실패한 경우에 대한 처리도 가능하다.

Promise 사용 목적

서버에서 데이터를 받아올 때 의도치 않게 데이터를 다 받아오지 못했는데도 화면에 표시하려 하면 이는 오류로 처리되거나 빈 데이터로 표시된다.
이런 상황에 대한 처리를 할때 사용하는 방법 중 하나가 Promise다.
즉, 자바스크립트에서 오류나 예외처리가 필요할 때 사용할 필요가 있다.

Promise 동작 예제

1
2
3
4
5
6
7
8
9
function getData(callbackFunc) {
  $.get('url 주소/products/1'function(response) {
    callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
  });
}
 
getData(function(tableData) {
  console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});
 

제이쿼리의 ajax 통신 API를 이용하여 지정된 url에서 1번 상품 데이터를 받아오는 코드다.
콜백 함수를 이용하여 비동기 처리가 되었다.
getData 선언 후 function(tableData) 이라는 즉시실행 함수를 인자로 실행
jquery의 get 기능 사용으로 받아온 응답을 callbackFunc 를 실행하는 것으로 마무리한다.
callbackFunc는 위에 소스에선 function(response)가 될것이다.

그러나 꼭 이렇게 소스를 분리해서, 기능을 구현 할 필요가있는가??
개인적인 생각으로 하나의 펑션에 여러기능을 모아놓는것은 나중에 유지보수가 어렵기 때문에 분리해서 작성하는 거라 생각한다.

위의 소스를 Promise를 사용해서 작성한다면 아래처럼 될것이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getData(callback) {
  // new Promise() 추가
  return new Promise(function(resolve, reject) {
    $.get('url 주소/products/1'function(response) {
      // 데이터를 받으면 resolve() 호출
      resolve(response);
    });
  });
}
 
// getData()의 실행이 끝나면 호출되는 then()
getData().then(function(tableData) {
  // resolve()의 결과 값이 여기로 전달됨
  console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});
 

콜백 함수로 처리하던 구조에서 new Promise(), resolve(), then()와 같은 프로미스 API를 사용한 구조로 바뀌었다.
이 구조를 이해하기위해 프로미스의 상태에 대해 알아야한다.

Promise의 3가지 상태(States)

상태란 즉 Promise의 처리 과정을 의미한다.
new Promise()를 통해 생성하면 종료할때까지 3가지 상태를 가진다.

  • Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
  • Fulfilled(이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
  • Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태
1
new Promise();
1
2
3
new Promise(function(resolve, reject) {
  // ...
});
 

위처럼 new Promise() 메서드를 호출하면 대기(Pending) 상태가 된다.
new Promise() 메서드를 호출할 때 콜백 함수를 선언할 수 있고, 콜백 함수의 인자는 resolve, reject 가 된다.

여기서 콜백 함수의 인자 resolve를 아래와 같이 실행하면 Promise는 이행(Fulfilled) 상태가 된다.
new Primise를 동작시키지 않았다면 

1
2
3
new Promise(
function(resolve, reject) { resolve(); }
);
 

이행(Fulfilled) 상태가 되어야 then()을 통해 resolve라는 결과값을 받는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getData() {
      return new Promise(    function(resolve, reject) {
           console.log("in promise");
           console.log("resolve : "+resolves);
           console.log("reject : "+reject);
            var data = 100;
          resolve();
            //resolve(data);
            console.log("out promise");
            }
      );
    }
 
    // resolve()는 then 안에 들어간 내용으로 실행됨
    getData().then( 
        function() {  console.log("then() function(resolvedData) : "+"1002"); // 100  
        }
    );
 

즉 new Promise()에는 동작시킬 함수 객체 하나를 인자로 넣을수 있다.
인자는 즉시실행함수로 resolve용도, reject용도로 사용될 인자 2개를 넣는다.(이름은 마음데로 해도됨)
then에도 동작시킬 함수 객체 하나를 인자로 넣을 수 있으며, resolve용도로 선언된 인자가 호출된다면
then에서 동작시킨 함수 객체 하나가 실행된다.
위 소스의 결과를 보며 이해해보면 다음과 같다.

then에서 동작시킬 함수 객체에도 인자를 넣어서 수행시킬 수 있다.
다음 예제를 보면 알 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function getData() {
      return new Promise(    function(resolve, reject) {
              console.log("in promise");
              console.log("resolve : "+resolves);
              console.log("reject : "+reject);
            var data = 100;
            //resolve();
            resolve(data);
            console.log("out promise");
            }
      );
    }
 
    // resolve()의 then안에 들어간 내용으로 실행되며 인자를 추가하여 이용가능
    getData().then( 
        function(edData) {  console.log("then() function(edData) : "+edData); // 100  
        }
    );
 

위의 소스에서 reject를 아래와 같이 호출하면 실패(Rejected) 상태가 된다.
그리고 실패했을 경우에 대한 처리를 catch()를 통해 처리한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function getData() {
      return new Promise(    function(resolve, reject) {
              console.log("in promise");
              console.log("resolve : "+resolve);
              console.log("reject : "+reject);
            var data = 100;
            //resolve();
            //resolve(data);
            reject();
            //reject(new Error("Why so Serius~a"));
            console.log("out promise");
            }
      );
    }
 
    // resolve()의 결과 값 data를 resolvedData로 받음
    getData().then( 
        function(edData) {  console.log("then() function(resolvedData) : "+edData); // 100  
        }
    ).catch(
        function() { console.log("error info : "+"i Dnt know"); }
        //function(whaterror) { console.log("error info : "+whaterror); }
    );
 

reject 인 경우에도 인자를 추가하여 catch()를 실행할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function getData() {
      return new Promise(    function(resolve, reject) {
              console.log("in promise");
              console.log("resolve : "+resolve);
              console.log("reject : "+reject);
            var data = 100;
            //resolve();
            //resolve(data);
            //reject();
            reject(new Error("Why so Serius~a"));
            console.log("out promise");
            }
      );
    }
 
    // resolve()의 결과 값 data를 resolvedData로 받음
    getData().then( 
        function(edData) {  console.log("then() function(resolvedData) : "+edData); // 100  
        }
    ).catch(
        //function() { console.log("error info : "+"i Dnt know"); }
        function(whaterror) { console.log("error info : "+whaterror); }
    );
 

위 예제들을통해 3가지 상태에 대해서 쓰이는 조합은 아래와 같을것이다.

  • Pending(대기) : new Promise(function(resolve, reject) { ~~~ } )
  • Fulfilled(이행) : resolve() 와 .then()
  • Rejected(실패) : reject() 와 .catch()

Promise를 제대로 사용하기 위해선 위 조합들을 다 활용하는것이 좋을 것이라 생각한다.
그래야 데이터를 받거나 어떤 처리를 진행하는데 있어 성공이나 실패에 따른 결과를 알 수 있기 때문이다.
이처럼 중간에 확인이 필요한경우 사용하면 좋은 기능이라 생각한다.

javascript도 배울점이 많구나...