Promise 정리

The boxer·2021년 11월 15일
  • javascript에서 Promise를 사용해 sleep 함수를 구현한다.
  • 구현하면서 Promise에 대해 이해한 점을 정리해본다.

    Promise를 사용한 sleep 구현

const sleep = (time: number) => {
    return new Promise((res) => {
        setTimeout(res, time);
    })
}

Promise

  • Promise는 약속이다. javascript에서 시간이 오래 걸리는 로직(IO 작업)이 발생하면 이를 이벤트 큐에 삽입하고, 작업이 완료되면 결과를 받아볼 수 있게 한다.
    • Promise는 메인 쓰레드에게 말한다. '시간이 오래 걸리는 작업이 있으니 이것은 이벤트 큐에 넣어 완료될 때 까지 기다릴게. 완료되면 너가 받아 볼 수 있게 해줄게'
    • 메인 쓰레드는 시간이 오래 걸리는 작업을 Promise에게 위임하고, 나중에 작업이 완료되면 Promise가 이를 메인 쓰레드에게 알려 결과를 받아볼 수 있게 한다.
  • 위 예시에서 setTimeout 시간이 오래 걸리는 로직이며, Promise는 이 작업이 완료되면 메인 쓰레드에게 알린다.

해결하는 문제

  • 기존에 callback 방식은 함수를 실행하면서 함수의 로직이 종료된 이후에 실행될 로직을 함수로 받아 실행시켰다.
  • 대부분 아는 이야기겠지만, 이는 callback 지옥을 생성하여 코드의 가독성이 낮아졌으며, 에러 처리도 어려웠다.
  • Promise 는 이 두가지 문제를 해결한다
    • callback 지옥을 없애는것
    • 에러처리가 쉽도록 하는것

기본 사용

  • 간단한 Promise 구문을 살펴보자
function foo(flag: boolean) {
	return new Promise((res, rej) => {
		if(flag) {
        	res('suc');
        } else {
            rej('fail');
        }
	})
}

foo(true).then((res) => {
    console.log(res);
}, (rej) => {
    console.log(rej);
});

foo(false).then((res) => {
    console.log(res);
}, (rej) => {
    console.log(rej);
});

resolve, reject

  • Promise는 기본적으로 2개의 인자를 받는 익명함수를 생성자의 인자로 받는다.
  • 인자로 들어가는 함수의 인자는 모두 함수이며,resolve, reject라고 지칭된다.
  • 두 함수는 수행하는 역할이 다른데, Promise의 함수가 실행되는 도중 비정상적인 실행 혹은 실패할 경우 reject가 실행되며, 정상 실행의 경우 resolve가 실행된다.

then 구문

  • Promise를 리턴하면 이를 호출하는 부분에서 then 구문을 사용하여 결과를 받아볼 수 있다.
  • then 구문의 로직은 호출된 함수와 Promise 내부의 함수 로직이 모두 마무리 되면 실행된다.
  • then 구문은 onFulfilled, onRejected 라는 2개의 함수를 인자로 받으며, 각 함수는 하나의 인자를 받는다.
  • 각 함수는 수행하는 수행하는 역할이 다른데, 첫번째 인자로 들어가는 함수는 Promise에서 resolve가 호출되었을 때 실행되며, 두번째 인자로 들어가는 함수는 reject가 호출되었을 때 실행된다.
  • 그리고 각 resolvereject가 실행될 때 input으로 들어가는 값은 onFulfilled, onRejected의 인자로 전달된다.

위 예시의 결과

  • 예시의 foo 함수에 true를 input으로 넣으면 함수 내부에서 flag 값에 의해 res로 지칭된 함수가 실행되며, false를 넣으면 rej가 실행된다.
  • res, rej 가 실행되면서 input으로 넣어지는 인자는 then 구문의 인자로 전달된다.
  • 따라서, foo에 true를 전달하면 'suc'가 출력되며, false를 전달할 경우 'fail'이 출력된다.

에러처리

  • 위 예시는 단순히 분기처리에 의해 resolvereject의 호출을 나뉘었다.
  • Promise는 에러처리가 쉽도록 하는것을 해결한다고 했다. 다음 예시를 보자.
function doError() {
    return new Promise((res, rej) => {
        throw new Error('throw error');
    });
}

doError().then((res) => {
    console.log('success');
}, (rej) => {
    console.log('catch error');
})
  • doError 함수는 error를 throw하는 Promise를 반환한다.
  • 그리고, 이를 호출하는 부분에서는 Promise의 결과에 따라 'success'나 'catch error'를 출력하게 된다.
  • 기본 사용 예시에서 Promise 내부의 함수에서 에러가 발생하면 reject가 실행된다고 했다.
  • 그리고, reject가 실행되면, then 구문에서는 onRejected 가 실행된다고 했다.
  • 위 예시에서 Error를 던지는 순간 reject가 실행되며, 이를 호출하는 부분에서는 onRejected를 실행한다.
  • 따라서, 위 예시에서 catch error가 출력된다.

sleep

  • 이제 위의 sleep 함수를 다시 보자.
const sleep = (time: number) => {
    return new Promise((res) => {
        setTimeout(res, time);
    });
}

sleep(3000).then((res) => {
    console.log('foo');
})
  • Promise의 인자로 time이라는 시간 뒤 res를 실행시키는 setTimeout을 전달한다.
  • sleep 함수는 해당 Promise를 반환한다.
  • sleep을 호출하는 부분에서 sleep의 인자로 시간을 전달하고, then 구문으로 결과를 받아본다.
  • setTimeout이 resolve를 실행시키므로, then 구문에서는 onFulfilled를 실행하게 된다.
  • 따라서, 위 예시에서 sleep에 전달된 시간 이후 then 구문의 onFulfilled 부분이 실행되며, 3초 후 'foo' 가 출력된다.

틀린내용 혹은 수정이 필요한 부분이 있으면 말씀해 주시기 바랍니다.

profile
안녕하세요

0개의 댓글