본문 바로가기

Javascript/Javascript(ES6)

ES6 프로미스(Promise), 진짜 쉽게 이해하기 (Promise의 목적만 생각한다.)

반응형

프로미스(Promise)

싱글쓰레드인 자바스크립트에서 비동기 처리를 위해서 콜백(callback)을 사용해왔다.

덕분에 비동기 처리를 온전히 해낼 수 있었지만 이런 콜백이 사용되는 경우가 많아지면서 단점이 드러났다.

그 단점은 비동기 처리를 순차적으로 실행할 필요가 있는 경우에 비동기 처리를 중첩시켜서 표현하므로 에러, 예외처리가 어렵다는 것과 중첩으로 인한 복잡도가 증가하는 것이 이다.

크게 이 두 가지의 단점을 해결하기위해 프로미스가 예전부터 라이브러리로 생겨났고, 이것을 ES6에서는 언어적 차원에서 지원하게 되었다.


Promise를 이해하기 위해 여러 블로그를 돌아다니며 찾아본 결과 핵심은 이 프로미스의 목적만 머릿속에 집어넣는 것이고, 딱 한 번만 따라 쳐보면 이해가 된다.

"비동기에서 성공과 실패를 분리해서 메서드를 수행한다."

예외 처리 실패 예시

1
2
3
4
5
6
try {
  setTimeout(() => { throw 'Error!'; }, 1000);
catch (e) {
  console.log('에러를 캐치하지 못한다..');
  console.log(e);
}
cs

try-catch에서 비동기 함수의 콜백메서드에서 에러를 만들지만 catch하지 못한다.

(setTimeout()함수의 콜백은 이벤트큐에 있다가 콜스택이 비어지면 실행되기 때문)

고로 콜백메서드의 중첩은 에러 처리가 힘들다.

프로미스 생성, 실행

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//프로미스 생성
const promise1 = function(param){
  return new Promise(function(resolve,reject){
    if(param){
      resolve("바보");
    }
    else{
      reject("아닌데");
    }
  });
}
//프로미스 실행
promise1(true).then(function(result){
  console.log(result);//바보
},function(err){
  console.log(err);//아닌데
});


프로미스의 생성 방법은 new Promise((resolve, reject){...}) 로 생성하는 방법이다.

promise1 함수를 보면 프로미스를 리턴하는데 이것은 프로미스안에서 비동기함수를 실행하고(위의 예제는 단순히 파라미터로 true, false) 성공했을 때 resolve()를 실행하고 실패 또는 에러가 났을 때 reject()를 실행한다.

그러면 resolve()랑 reject()는 나중에 함수를 실행할 때 .then(success, fail)메서드로 수행하면 된다.

* 프로미스는 상태를 갖는다. (쉽게 fulfilled, rejected 두 개만 기억, fulfilled상태면 resolve()실행, rejected면 reject()실행)


결국 비동기함수를 만들어서 사용해야할 때 프로미스 객체를 리턴하게 만들어서 사용하면 콜백 헬(콜백 중첩)을 방지할 수 있고 에러처리를 수월하게 할 수 있다는 이야기다.

누군가 만든 비동기함수 역시 프로미스 객체를 리턴하게 만들어 놨으므로 promise를 실행(.then 또는 .catch)하면 된다.


비동기 함수 중간에 에러가 난다면..? Promise.catch()

1
2
3
4
5
6
7
8
9
asyncThing1()
    .then(function() { return asyncThing2();})
    .then(function() { return asyncThing3();})
    .catch(function(err) { return asyncRecovery1();})
 
    .then(function() { return asyncThing4();}, function(err) { return asyncRecovery2(); })
    .catch(function(err) { console.log("Don't worry about it");})
 
    .then(function() { console.log("All done!");});
cs

비동기 메서드가 프로미스 객체를 리턴하면 계속해서 .then, .catch하는 식으로 체이닝이 가능하다.

.catch는 비동기 메서드중에 에러가 나면 캐치가 가능하게 해준다.

<그림 출처 : http://programmingsummaries.tistory.com/325>

그림이 너무 좋아서 가져왔다. 성공(녹색선)과 실패(빨간선)했을 때는 잘 따라오면서 보면 이해가 된다.

여러 개의 프로미스가 모두 완료되었을 때 실행하는 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const param = true;
const promise1 = new Promise(function(resolve,reject){
    if(param){
      resolve("바보");
    }
    else{
      reject("아닌데");
    }
});
const promise2 = new Promise(function(resolve,reject){
    if(param){
      resolve("바보2");
    }
    else{
      reject("아닌데2");
    }
});
Promise.all([promise1,promise2]).then(function(values){
    console.log("1,2,3 모두완료",values);
});


Promise.all()을 사용하면 파라미터로 갖는 모든 프로미스가 완료되면 수행하고 프로미스들의 값을 보여준다.

결과=>

1,2,3 모두완료

[바보, 바보2]


참고사이트

http://poiemaweb.com/es6-promise

http://blog.jeonghwan.net/2016/04/28/es6.html

http://programmingsummaries.tistory.com/325

반응형
  • 아이쿠 2019.01.14 17:57

    프로미스 여러개 돌리는데

    const param = true;

    인자값으로 전역변수를 써야하나요?
    이러면 안되는데...

    • 문제가 있으신가요..?

      전역변수아니어도 상관없습니다.
      const promise1 = new Promise(function(resolve,reject){
      const b = true;
      if(b){
      resolve("바보");
      }
      else{
      reject("아닌데");
      }
      });
      const promise2 = new Promise(function(resolve,reject){
      const c = true;
      if(c){
      resolve("바보2");
      }
      else{
      reject("아닌데2");
      }
      });
      Promise.all([promise1,promise2]).then(function(values){
      console.log("1,2,3 모두완료",values);
      });

  • Favicon of https://balmostory.tistory.com BlogIcon 발모스토리 2020.12.19 18:12 신고

    덕분에 좋은 공부했습니다.
    제가 공부한 내용인데 시간되시면 한 번 들려주세요 ㅎㅎ
    https://balmostory.tistory.com/68