본문 바로가기
Programming/Javascript

[Javascript] 프로미스(promise) 객체

by Bam_t 2021. 5. 24.
728x90

자바스크립트로 비동기 처리를 하는 경우에는 콜백 함수를 이용했었습니다. 그러나 콜백 함수는 문제점이 많았기에 이러한 현상을 해결할 대안으로 프로미스 객체를 ES2015에서부터 도입하게 됩니다. 이 객체도 또한 자바스크립트의 내장 객체입니다.

 

콜백 함수를 다루지 않았어서 간단하게 설명하고 넘어가려고 합니다.

콜백 함수(CallBack Function)이란 나중에 호출되는 함수입니다. 비록 콜백 함수라고 명명되어있기는 하지만 일반적인 자바스크립트 함수와 똑같습니다. 다만 차이점으로는 코드에서 명시적으로 호출되는 것이 아닌, 특정 시점이나 이벤트의 발생에 따라 시스템에서 호출되는 함수입니다.

더 간단하게 정리하자면, 문법적으로는 일반 함수들과 차이는 없지만 호출 방식이 다르다 정도입니다.


1. 왜 프로미스 객체가 등장했는가

기존 콜백 함수 방식은 비동기 처리에 적합했으나 비동기 처리들이 연속될경우 가독성을 해치고 코드가 난잡해진다는 점이 있습니다.

1번 콜백 함수 {
	2번 콜백 함수 {
    		3번 콜백 함수 {
        		4번 콜백 함수 {
            			5번 콜백 함수 {
                }
            }
        }
    }
}

물론 한글로만 써놔서 간단해 보이지만 실제 구문으로 옮기면 콜백 함수의 처리 내용이라던가, function 명령이라던가 붙으면서 굉장히 어지러워 지게됩니다.

이런 현상을 콜백 지옥이라고 부르며 이런 현상을 간결한 코드로 바꾸면서 해결해 준 것이 프로미스 객체입니다.

 

 

 

 

2. 프로미스 객체

프로미스 객체의 기본 사용법은 다음과 같습니다.

const promise = new Promise((resolve, reject)=>{
	//처리 내용
});

이때 프로미스 객체의 resolve는 비동기 처리의 성공을, reject는 비동기 처리의 실패를 알리기 위한 함수들입니다.

 

이렇게 비동기 처리를 다루기 위해 promise 다음엔 then()과 catch()따라옵니다.

const promise = new Promise((resolve, reject)=>{
	//처리 내용
});

promise.then(
	//resolve가 호출되면 then이 실행
)
.catch(
	//reject가 호출되면 catch가 실행
)
.finally(
	//콜백 작업을 마치고 무조건 실행되는 finally (생략 가능)
)

then()은 생성한 프로미스 객체에서 인수로 전달한, resolve가 호출되면 then() 부분이 실행이 되고, reject가 호출이 된다면 catch부분이 실행이 됩니다.

 

사실 이렇게 읽으면 감이 잘 오지 않으므로 예제를 하나 만들었습니다.

const flag = true;
const promise = new Promise(((resolve, reject) => {
    if (flag) {
        resolve('resolve가 되었음');
    }
    else {
        reject('reject가 되었음');
    }
}));

promise.then((resolveMessage) => {
    console.log(resolveMessage);
})
.catch((errorMessage) => {
	console.log(errorMessage);
});

flag가 true면 resolve를 호출하고 false면 reject를 호출합니다.

resolve와 reject는 각각 호출되며 인수로 문자열을 전달합니다.

 

여기선 flag를 true 주었기 때문에 then()이 실행되어 resolve의 인수로 전달된 메세지가 출력되었음을 볼 수 있습니다. 만약 flag가 false라면, reject의 인수가 전달된 catch가 실행되어 errorMessage가 출력됩니다.

 

 

 

 

3. 프로미스 객체로 비동기 처리 연결하기

then()과 catch() 뒤에는 또다른 then()과 catch()를 연결함으로써 비동기 처리를 연결할 수 있습니다. 위의 예제를 변형해서 비동기 처리들을 연결해보겠습니다.

const flag = true;
const promise = new Promise(((resolve, reject) => {
    if (flag) {
        resolve('resolve가 되었음');
    }
    else {
        reject('reject가 되었음');
    }
}));

promise.then((resolveMessage) => {
    console.log(resolveMessage);

    return new Promise(((resolve, reject) => {
        if (flag) {
            resolve('resolve가 되었음2');
        }
        else {
            reject('reject가 되었음2');
        }
    }));
})
.then((resolveMessage2)=> {
    console.log(resolveMessage2);
})
.catch((errorMessage) => {
    console.log(errorMessage);
});

첫 번째 then()이후에 또 다른 then()을 연결했음을 볼 수 있습니다.

이때 return으로 다음 then() 혹은 catch()의 실행을 위한 resolve와 reject 호출을 반환하게 되고, 이 반환 결과에 따라 다시 한 번 then()/catch()를 실행하게 됩니다.

 

 

 

 

4. 여러개의 프로미스를 한 번에처리하기 

방금전에 본 방식은 then()과 catch()를 나열해서 순차적으로 처리한 방식이었습니다. 이번에는 한 번에 병행처리하는 방식을 알아보겠습니다.

 

비동기의 병행처리 방식은 all()이라는 메소드를 이용하며, 다음과 같은 구조를 갖습니다.

Promise.all(
	//병행 처리할 Promise 객체들
)

 

메소드의 인수로 프로미스 객체들을 대괄호([ ])를 이용하여 전달합니다. 실제 사용 예를 보여드리겠습니다.

const promise1 = new Promise((resolve, reject) => {
    resolve('resolve 되었음1');
});
const promise2 = new Promise((resolve, reject) => {
    resolve('resolve 되었음2');
});
const promise3 = new Promise((resolve, reject) => {
    resolve('resolve 되었음3');
});

Promise.all([
    promise1,
    promise2,
    promise3,
])
.then((message) => {
	console.log(message);
})
.catch((errorMessage) => {
	console.log(errorMessage);
});

생성한 promise1~3은 모두 resolve만을 반환하는 프로미스입니다.

 

Promise.all()은 인수로 전달한 프로미스 객체들이 모두 resolve를 호출하는지 검사합니다. 만약에 전달된 프로미스 객체들이 모두 resolve를 호출 했다면 then()을 실행하고, 하나라도 reject를 호출한다면 catch()를 실행하게 됩니다. 기존 콜백식으로 표현했다면 여러번의 중첩으로 코드가 난잡해졌을텐데 all()메소드로 간결하고 직관적이게 표현이 되었습니다.

 

 

 

 

5. 기타 프로미스 객체의 메소드들

5-1. resolve(), reject()

resolve()와 reject()는 각각 resolve를 즉시 호출하는 프로미스, reject를 즉시 호출하게 하는 프로미스를 만드는 메소드입니다.

Promise.resolve(param);
Promise.reject(param);

 

const promise1 = Promise.resolve('resolve가 되었음');
const promise2 = Promise.resolve('reject가 되었음');

promise1.then((resolveMessage)=>{
    console.log(resolveMessage);
})
.catch((rejectMessage)=>{
    console.log(rejectMessage);
});

promise2.then((resolveMessage)=>{
    console.log(resolveMessage);
})
.catch((rejectMessage)=>{
    console.log(rejectMessage);
});


5-2. race()

race() 메소드는 all()처럼 사용합니다. race()의 기능은 인수로 전달한 프로미스 객체들 중 하나가 먼저 완료됬을 경우 then()을 호출합니다.

Promise.race(
	//프로미스 객체들
)

 

병행 처리에서 봤던 all()메서드 예제를 race()로 변경한 예제를 보여드리겠습니다.

const promise1 = new Promise((resolve, reject) => {
    resolve('resolve 되었음1');
});
const promise2 = new Promise((resolve, reject) => {
    resolve('resolve 되었음2');
});
const promise3 = new Promise((resolve, reject) => {
    resolve('resolve 되었음3');
});

Promise.race([
    promise1,
    promise2,
    promise3,
])
.then((message) => {
    console.log(message);
})
.catch((errorMessage) => {
    console.log(errorMessage);
});

본 예제에서는 promise1 객체가 먼저 실행되므로 항상 결과는 1만 나오지만, 다른 예제를 가지고 할 경우 처리 속도에 따라 결과가 계속 바뀔 수 도 있습니다.


참조

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise

 

Promise - JavaScript | MDN

Promise 객체는 비동기 작업이 맞이할 미래의 완료 또는 실패와 그 결과 값을 나타냅니다.

developer.mozilla.org

 

728x90

'Programming > Javascript' 카테고리의 다른 글

[Javascript] 웹 스토리지 Web Storage  (0) 2021.10.02
[Javascript] async/await  (0) 2021.05.24
[Javascript] 예외 처리 try~catch~finally  (0) 2021.05.20
[Javascript] 전개 연산자  (0) 2021.05.07
[Javascript] 구조 분해 할당  (0) 2021.05.07

댓글