#6 Promise

20258 단어 JavaScriptJavaScript

Introduce

본 문서는 2022년 4월 17일 에 작성되었습니다.


Thoery

JavaScript 는 기본적으로 Synchronouse, 동기, 결과를 기다리지 않는 방식으로 진행됩니다.
그러나 특정한 경우에 Asynchronouse, 비동기, 결과를 기다리는 방식으로 진행됩니다.


Promise

전술한 Asynchronouse 를 위해서 ES5 에서 추가된 기능이 Promise 입니다.

JavaScript 에는 fetch 와 같이 서버 외부와 통신할 상황이 존재합니다.
이러한 외부 호출 상황에서는 값의 반환을 기다려야 하는 상황 이 발생합니다.
또한 호출 결과에 따라서 이후의 로직이 달라져야 할 것입니다.

이러한 상황에서 쓸 수 있는 것이 Promise 이며,
프로토타입 객체를 생성하는 것으로 구현할 수 있습니다.

constructor

new 키워드가 붙은 생성자를 통해서 Promise 프로토타입 객체를 만들 수 있습니다.
해당 객체는 성공한 결과를 위한 resvole실패한 결과를 위한 reject 함수가 있습니다.

new Promise((resolve, reject) => { 
  
  // 비즈니스 결과...
  
  if (isSuccess) resolve('Success!');
  else reject('Fail!');
  
});

then, catch

이러한 Promise 의 결과를 사용하기 위해서
성공한 결과를 위한 then실패한 결과를 위한 catch 함수가 있습니다.

const promise = new Promise((resolve, reject) => { ... });
promise
  .then(resolvedValue => console.log(resolvedValue))
  .catch(erroredValue => console.log(erroredValue));

그 중에서 then 은 chaining then 으로 사용할 수 있습니다.
단, n 회차의 then 에서는 n-1 회차의 return value 를 사용하게 됩니다.

const promise = new Promise((resolve, reject) => { ... });
promise
  .then(resolvedValue => resolvedValue)
  .then(resolvedValue => resolvedValue)
  .then(resolvedValue => resolvedValue)
  .then(resolvedValue => resolvedValue)
  .then(resolvedValue => console.log(resolvedValue))
  .catch(erroredValue => console.log(erroredValue));

Promise.all([])

Promise.all 은 n개의 Promise 를 실행하게 됩니다.
역시나 성공한 결과를 위한 then 이 있고 하나라도 실패할 경우 프로세싱을 중단하고 catch 합니다.

Usage

const promise1 = new Promise((resolve, reject) => { ... });
const promise2 = new Promise((resolve, reject) => { ... });
const promise3 = new Promise((resolve, reject) => { ... });
                                                  
Promise.all([promise1, promise2, promise3])
  .then(resolve => console.log(resolve))
  .catch(reject => console.log(reject));

More

예상 되는 예시로는 하나의 프로세스가 n 개의 독립 프로세스로 분리되는 경우 가 있을 것입니다.

만약 n 개의 도서 API 을 이용한 서비스가 존재하고 단위 호출의 소모 비용 이 주어졌다고 합시다.

  1. 호출 전송 0.01s
  2. 결과 대기 10s
  3. 결과 사용 0.01s

n 개의 호출을 순차적으로 처리 할 경우의 기대 비용은 다음과 같을 것입니다.

0.01n+0.01n+10n=10.02n0.01 * n + 0.01*n+10n =10.02n

하지만, n 개의 호출을 전부 동시에 처리 할 경우의 기대 비용은 다음과 같을 것입니다.

0.01+0.01+10=10.02+delayTime(byPromise)0.01 + 0.01 + 10 = 10.02 + delayTime(byPromise)

물론 이러한 동시 호출의 경우 다음과 같은 이슈가 발생할 수 있을 것입니다.

  1. 1개의 호출만 길어지는, 최악의 경우 가 존재
  2. 서로 독립적인 상황이여야 하기 때문에, 제한된 사용 상황 의 제약

그러나 분명히 Velog - unchaptered / Mongoose - Advanced 에서 사용한 Promise.all() 과 같은 사용으로 효과적인 DB 통신 성능의 향상 을 이뤄낼 수 있을 것이라고 기대됩니다.

최근 User 와 Room 이라는 모델이 양방향 참조 되어 있는 경우, 다음 프로세스를 구현했습니다.

  1. 초대장 발송 / 수락 / 거절
  2. 입장권 신청 / 수락 / 거절

서비스 품질을 위해서 클라이언트가 특정한 n 명 의 Document 를 변경해야 헀습니다.
mongoose 의 N+1 문제배열에 중복값이 들어가는 문제 를 해결하기 위해서 다양한 $ 키워드를 사용했습니다.

하지만 이러한 비즈니스 로직에는 아직 Transaction 이 미적용 되어있는 상태입니다.
이러한 경우 데이터의 일부만 수정되는 상황 이 발생할 수 있으며 서비스 품질이 떨어지는 일을 낳게 될 것입니다.

따라서,
Promise.all([]) 을 이용한 DB 수정의 경우,
최종적으로 catch() 로 문제를 확인하고, 문제가 없을 경우에 Transction 을 반영 해야 할 것입니다.


Promise.race([])

Promise.race 은 n개의 Promise 를 실행하게 됩니다.
특이한 점은 최초 성공을 위한 then최초 실패를 위한 catch 만 존재한다라는 점입니다.

Usage

const promise1 = new Promise((resolve, reject) => { ... });
const promise2 = new Promise((resolve, reject) => { ... });
const promise3 = new Promise((resolve, reject) => { ... });
                                                  
Promise.race([promise1, promise2, promise3])
  .then(resolve => console.log(resolve))
  .catch(reject => console.log(reject));

좋은 웹페이지 즐겨찾기