비동기코드 하면 나오는 단어중 하나가 콜백헬입니다.

코드의 많이 중첩되어서, 가독성이 매우 떨어지는 문제를 애기하는 것으로 JavaScript 에서도 여러가지 대안들이 나왔었습니다.

이에 대한 대안중 하나가 Promise인데요. 이것은 Javascript es6에 채택이 되었습니다.

오늘은 이 Promise에 대해서 정리해 보겠습니다.

 

1. Promise

비동기 이벤트의 처리의 완료 또는 실패를 나타내는 객체를 가르킵니다.

콜백헬에 빠지지 않고, 비동기 처리가 성공한 경우와 실패한 처리를 구분할 수 있는데요.

Promise는 비동기 operation에 대한 상태들을 아래와 같이 정의하고 사용합니다.

 

상태 내용
pending Promise의 initial (초기)상태
fulfilled 성공적으로 수행이 된 상태
예) get리퀘스트를 요청한 후, 성공적으로 JSON값을 받아온 경우
rejected 비동기 Operation 의 실패 상태

 

 

pending 상태에서 시작하여 fulfulled가 되거나 rejected가 되는데요. 

이 과정을 settle이된다고 표현 합니다.

그래서 크게보면, pending과 settled 두가지 State이 있는 것 이구요.

settled는 다시 fulfill과 rejected로 구분할 수 있는 것 이지요.

이정도 지식을 가지고 Promise객체를 만들어보면서 좀 더 알아가 보도록 하겠습니다.

 

2. Promise의 생성

Promise는 new 생성자를 사용해서 객체를 생성하는데요.

생성자는 인자로 resolve와 reject두개의 함수를 인자로 가진 함수를 받습니다.

(함수를 인자로 갖는 함수를 인자로 받는다는 말이 좀 복잡해 보이기는 합니다.)

 

resolve함수는 호출되면 Promise의 상태를 pending에서 fulfill로 변경시켜줍니다.

호출시에 resolve된 값을 resolve의 인자로 값을 넘겨줍니다.

reejct함수는 예상할 수 있듯이 Promise의 상태를 pending에서 reject로 변경시켜 줍니다.

그리고 reject된 원인을 reject의 인자로 넘겨줍니다.

 

 

 

이렇게 Promise에서 settle된 결과를 가지고 어떻게 할지에 대해서

코딩해 주어야 하는데요.

아래에서는 그 방법에 대해서 정리해 보겠습니다.

 

 

3. then과 catch

 

Promise에서 실행함수를 임자로 넘겨주어 객체를 넘겨주면, settle된 결과가 전달되는데요.

그 결과에 따라서 무엇을 수행해야 하는가를 then()메소드를 이용합니다.

영어로는 너무나 흐름이 잘 보이는 것 같은데요.

Promise(약속하고)=> Settle(결론이 나면)=> then(그러고 나면 ~해라) 하고, err가 나면, catch()를 사용할 수 있는 것 이지요.

참고로, then()의 인자에, successHandler와 ErrorHandler를 인자로 넣어줄수도 있습니다.

하지만, catch()로 하는것이 훨씬 더 명확해 보이겠지요.

 

 

 

4. Promise 의 체이닝

꼬리에 꼬리를 무는 비동기 operation 때문에 콜백헬이라는 말이 나왔는데요.

promise에서는 어떻게 비동기 operation 을 풀고 있는지 보도록 하겠습니다.

 

아래에서는 Promise에 alert를 랜덤하게 해주는 Promise를 체이닝 하도록 하였습니다.

마지막에는 onFulfilled시에 콘솔에 로그를 하고, onRejected시에도 로그를 남기도록 하였습니다.

chaining을 할 때 가장 주의할 점은, 

다음 promise를 호출하고자 할 경우는,  return 키워드를 잊지 않고 붙여주어야 한다는 점 입니다.

 

 

이번에는 catch다음에 then을 chaing해 보겠습니다.

catch다음에 then을 붙이면, exception처리의 finally랑 유사하게,

catch다음에 해당하는 then이 실행되게 됩니다.

 

new Promise((resolve, reject) => {
    console.log("test 시작");
    resolve();
})
.then(() => {
    throw new Error("에러 발생");
})
.catch((err) => {
    console.log(err)
})
.then(() => {
    console.log("catch후에 실행됨");
});

 

 

마지막으로 finally 도 사용해 보겠습니다.

reject되었건 resolve되었건간에, 마지막으로 실행이 되는 것 인데요.

아래에서는 API에 대한 request를 시작하기 전에, isLoading값을 true로 하였구요.

finally에서 false로 변경해 주었습니다.

 

 

 

5. Promise.all()

위에서 chaining하는 방법을 보았는데요.

Chaining에서는 A operation이 끝나고, A Operation이 onFulfilled인지 onRejected인지 settle된 상태에 따라서,

B operation이  실행되게 됩니다. 즉, Chaining을 따라서 순서를 가지게 된다는 것인데요.

이런 순서에 관계없이 비동기로 모든 operation을 실행시키려고 할 경우에는 all()메소드를 이용하면 됩니다.

 

Promise.all()메소드는 array로 promise들을 인자로 받는데요.

모든 Promise들이 onFulfilled가 되면, resolve된 value들의 array를 인자에 값으로 주게되구요.

then()에서 그 결과에 대한 처리를 해주면 됩니다.

하나라도 onRejected가 된다면 처리가 종료되고, catch에서 에러처리를 해주면 됩니다.

 

 

 

6. Promise.race()

조금 재미있는 API중 하나가 race()인데요.

이름에서 알 수 있듯이 가장 먼저 settle되어 resolve나 reject된 것을 실행하고 종료합니다.

아래 코드에서 console에 찍히는 값은 0.1초뒤에서 실행되는 p2 뿐 입니다.

 

 

7. Nested Promise

만약, Promise안에 Promise를 사용해야 하는 경우는 어떻게 해야할까요?

특히나, 첫번재 바깥쪽의 promise에서 값을 받아서 두번재 promise를 동작시키게 해야한다면 어떻게 해야할까요?

 

비동기 프로그래밍에서는 blocking하는 코드는 피해야 하겠지만,

전체 DB카운트를 받아서 그 값으로 무언가를 보여주거나 해야하는 경우등이 있을 수 있겠지요.

 

이 때 고려해야 할 것은,

then()에서 Promise 를 return할 수 도 있다는 점 입니다.

Promise.all()을 이용해서 첫번재 인자로 첫번째 프로미스에서 나온 값을 넣어주고,

두번째 인자로 실행되야할 secondPromise를 아래와 같이 넣어주면 되겠네요.

 

 

두번째 프로미스에서 아래와 같이 값을 넘겨서 다음에 또 사용할 수 있도록 넘겨준다든지 하는 것이 가능해 진다는 것이지요.

 

 

8. Promise와 setTimeout

setTimeout()을 사용하여 delay를 시켜서 Promise의 Chaing을 사용하고 싶다면,

Promise객체를 생성해서 아래와 같이 사용해주면 됩니다.

 

 

이렇게 해서, Promise의 사용법에 대해서 정리해 보았는데요.

좀 더 좋은 방법이나 API가 있다면, 이 글에서 업데이트하도록 하겠습니다.

 

728x90

+ Recent posts