RATSENO

[JS]Promise (프라미스) - 2 본문

DEV/JS

[JS]Promise (프라미스) - 2

RATSENO 2019. 11. 21. 09:30

이전 포스팅 : [JS]Promise (프라미스) - 1

에 이어서 이번에는 실무에서 자주 사용될 수 있는 여러 개의 프라미스를 연결해서 사용하는 케이스에 대해서 알아보도록 하겠습니다.

실무에서 개발을 진행하다 보면 화면구성에 필요한 API호출을 순차적으로 해야될 경우들이 자주 있습니다. 화면 구성을 위해서 1번, 2번, 3번 API가 필요할때 2번 API를 호출하기 위해서는 1번 API에서 얻은 값이 필요하고, 3번 API를 호출하기 위해서는 2번 API에서 얻은 값이 필요한 이러한 경우들을 예로 들수 있습니다.


3번 API → 2번 API → 1번 API

3번 API는 2번 API 결과값에 종속적

2번 API는 1번 API 결과값에 종속적


이렇게 순차적으로 호출하기 위해서는 주로 콜백함수를 이용하여 해결하지만, 경우의 수가 많아 질수록 콜백지옥이 벌어지는 경우가 대다수 입니다. 

프라미스여러 개의 프라미스를 연결하여 사용할 수 있다는 점을 이용하여, 콜백지옥에서 벗어날 수 있게 도와줍니다.

여러가지 케이스를 보며 이해를 해보도록 합시다.

 

이전 포스팅에서 사용하였던 countdown 함수를 이용해 보겠습니다. countdown 함수의 매개변수로 seconeds를 전달받고 카운트 다운이 끝난 후, 프라미스 객체를 반환할 때 매개변수로 받은 seconds를 resolve()에 담아 실행합니다.

그리고 전달 받은 seconds까지 다시 역순으로 count해주는 reverseCount함수를 만들어 봅시다.

function countdown(seconds){
	return new Promise(function(resolve, reject){
		for(let i=seconds; i>=0; i--){
			setTimeout(function(){
				if(i>0){
					console.log(i + "...");
				}else{
					resolve(seconds);
				}
			}, (seconds-i)*1000);
			//i가 5일때 -> (5-5)*1000 = 0 : 바로 출력
			//i가 4일때 -> (5-4)*1000 = 1000 : 1초 뒤 출력
			//i가 3일때 -> (5-3)*1000 = 2000 : 2초 뒤 출력
			//i가 2일때 -> (5-2)*1000 = 3000 : 3초 뒤 출력
			//i가 1일때 -> (5-1)*1000 = 4000 : 4초 뒤 출력
			//i가 0일때 -> resolve(console.log('GO!')); 실행 프로미스 반환
		}
	});
}

function reversCountdown(seconds){
	return new Promise(function(resolve, reject){
		for(let j=2; j<=seconds+1; j++){
			setTimeout(function(){
				if(j<seconds+1){
					console.log(j+ "...");
				}else{
					resolve(console.log('Reverse!'));
				}
			}, (j-2)*1000);
		}
	});	
}

이 두개의 비동기적 함수를 연결해 주기위해서는 then() 핸들러를 이용하여, countdown함수가 끝나게되면 reversCountdown함수가 실행되게 할 수 있습니다.

 

먼저 정상적으로 여러개의 프라미스를 연결하는 케이스에 대해서 작성해봅시다.

 

[1] 정상 동작하는 경우

countdown(3)
.then(reversCountdown);

3...
2...
1...
2...
3...
Reverse!


[2] 정상 동작하는 경우

countdown(3)
.then(function(seconds){
	reversCountdown(seconds);
});

3... 
2... 
1... 
2... 
3... 
Reverse!


위와 같이 두 함수가 Promise객체를 반환하기 때문에 then을 이용하여 순차적으로 실행되는것을 확인할 수 있습니다.

하지만 만약 저 두 함수의 연결 사이에 Promise객체를 반환하지 않는 일반적인 함수를 연결하게 되면 어떻게 될까요?

function noPromise(){
	//일반적인 함수
	console.log('No Promise');
	return;
}

 

[3] Promise객체를 사용하지 않는 함수가 중간에 연결될 때

countdown(3)
.then(noPromise)
.then(reversCountdown);

3...
2...
1...
No Promise

//reverseCountdown 함수가 실행되지 않는다.


[4] Promise객체를 사용하지 않는 함수가 중간에 연결될 때

countdown(3)
.then(function(){
	console.log('No Promise');
	return;
})
.then(reversCountdown);

3... 
2... 
1... 
No Promise

//reverseCountdown 함수가 실행되지 않는다.


위의 [3], [4] 예제와 같이 Promise객체를 리턴하지 않을 경우, 다음 then() 핸들러로 넘어가기 위한 resolve() 호출을 할 수 없기때문에 다음 로직을 이행할 수 없게됩니다.

 

[3], [4] 예제를 정상적으로 실행하기 위해서는 Promise객체를 사용하여야 합니다.

 

[5] [3]번 예제 수정

function noPromise(seconds){
	return new Promise(function(resolve, reject){
		console.log("전달된 seconds : " + seconds );
		resolve(seconds);
	});
}

noPromise 함수를 수정한 뒤

countdown(3)
.then(noPromise)
.then(reversCountdown);

3...
2...
1...
전달된 seconds : 3
2...
3...
Reverse!


[6] [4]번 예제 수정

countdown(3)
.then(function(seconds){
	return new Promise(function(resolve, reject){
		console.log("전달된 seconds : " + seconds );
		resolve(seconds);
	});
})
.then(reversCountdown);

3...
2...
1...
전달된 seconds : 3
2...
3...
Reverse!


순차적으로 정상동작 하는것을 확인할 수 있습니다.

물론 일반적인 함수를 가장 마지막 순서에 놓게되면 문제가 없습니다.

 

[7] 일반함수를 가장 마지막 순서에

countdown(3)
.then(reversCountdown)
.then(function(){
	console.log('No Promise');
});

 

위의 여러가지 예제를 이용하여 다양한 케이스를 확인해 보았습니다. Promise에는 더 다양한 기능들이 있습니다.

시간이 된다면 좀더 실습(?)을 진행해보고 포스팅을 해보도록 하겠습니다.

 

PS.

설명에 잘못된 부분이 있으면 언제든 지적 부탁드리겠습니다.

(부족한 실력이지만 실무중에 겪었던 경험을 공유하고자 작성한 포스팅이라 엉성할 수 있습니다.ㅠㅠ)

'DEV > JS' 카테고리의 다른 글

[JS]맵(Map)과 셋(Set) -1  (0) 2019.12.04
[JS]map(), reduce() 함수  (0) 2019.12.03
[JS]Promise (프라미스) - 1  (0) 2019.11.20
[JS]Ajax  (0) 2019.11.19
[JS]이벤트 버블링과 캡처링  (0) 2019.11.15
Comments