RATSENO

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

DEV/JS

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

RATSENO 2019. 11. 20. 12:20

프라미스


프라미스는 콜백의 단점을 해결하려는 시도 속에서 만들어졌습니다. 프로미스는 일반적으로 안전하고 관리하기 쉬운 코드를 만들 수 있게 됩니다.

 

프라미스가 콜백을 대체하는 것은 아닙니다. 사실 프라미스에서도 콜백을 사용합니다. 프로미스는 콜백을 예측 가능한 패턴으로 사용할 수 있게 하며, 프라미스 없이 콜백만 사용했을 때 나타날 수 있는 엉뚱한 현상이나 찾기 힘든 버그를 상당수 해결할 수 있습니다.

 

프라미스의 기본 개념은 간단합니다. 프라미스 기반 비동기적 함수를 호출하면 그 함수는 Promise 인스턴스를 반환합니다. 프라미스는 성공(fulfilled)하거나, 실패(rejected)하거나 단 두 가지뿐입니다. 프라미스는 성공 혹은 실패 둘 중 하나만 일어난다고 확신할 수 있습니다. 성공한 프라미스가 나중에 실패하는 일은 절대 없습니다. 또한, 성공이든 실패든 단 한번만 일어납니다. 프라미스가 성공하거나 실패하면 그 프라미스를 결정됐다(settled)고 합니다.

 

프라미스는 객체이므로 어디든 전달할 수 있다는 점도 콜백에 비해 간편한 장점입니다. 비동기적 처리를 여기서 하지 않고 다른 함수에서 처리하게 하고 싶다면 프라미스를 넘기기만 하면 됩니다. 

 

 

 

프라미스 만들기


프라미스는 쉽게 만들 수 있습니다. resolve(성공)와 reject(실패) 콜백이 있는 함수로 새 Promise 인스턴스를 만들기만 하면 됩니다. 프로미스는 프로미스 생성자를 사용하여 생성하게 됩니다. 이 생성자는 resolve(성공)와 reject(실패), 두 가지의 매개변수만 필요합니다.

var promise = new Promise(function(resolve, reject){
	 /* Promise content */ 
	});

카운트다운을 셀 수 있는 countdonw은 함수를 작성해봅시다. 매개변수를 받게 만들어서 5초 카운트다운에 매이지 않게 하고, 카운트다운이 끝나면 프라미스를 반환하게 하겠습니다.

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(console.log('GO!'));
				}
			}, (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!')); 실행 프로미스 반환
		}
	});
}

 

프라미스 사용


countdown 함수를 어떻게 사용하는지 알아봅시다. 프라미스는 무시해버리고 countdown(5) 처럼 호출해도 됩니다. 카운트다운은 여전히 동작하고, 무슨 말인지 알기 어려운 프라미스는 신경쓰지 않아도 됩니다. 하지만 프라미스의 장점을 이용하고 싶다면 어떻게 해야 할까요? 반환된 프라미스를 사용하는 예제를 살펴봅시다.

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(console.log('GO!'));
				}
			}, (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!')); 실행 프로미스 반환
		}
	});
}

countdown(5).then(/* resolve() */function(){
	console.log('countdown completed sucessfully');
}, /* reject() */function(err){
	console.log('countdown experienced an error' + err.message);
})

이 예제에서는 반환된 프라미스를 변수에 할당하지 않고 then 핸들러를 바로 호출했습니다. then 핸들러성공 콜백에러 콜백을 받습니다. 경우의 수는 단 두가지 뿐입니다. 성공 콜백이 실행되거나, 에러 콜백이 실행되거나 입니다.

프라미스는 catch 핸들러도 지원하므로 핸들러를 둘로 나눠서 써도 됩니다.

 

[1] then() 핸들러에서 성공 콜백, 에러 콜백으로 처리한 경우

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{
					return reject(new Error("ERROR!"));
					//resolve(console.log('GO!'));
				}
			}, (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!')); 실행 프로미스 반환
		}
	});
}

const timer = countdown(5);

timer.then(/* resolve() */function(){
	console.log('countdown completed sucessfully');
}, /* reject() */function(err){
	console.log('countdown experienced an error ' + err.message);
})

출력 결과

5...
4...
3...
2...
1...
countdown experienced an error ERROR!


[2]catch() 핸들러를 이용하여 처리한 경우

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{
					return reject(new Error("ERROR!"));
					//resolve(console.log('GO!'));
				}
			}, (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!')); 실행 프로미스 반환
		}
	});
}

const timer = countdown(5);

timer.then(/* resolve() */function(){
	console.log('countdown completed sucessfully');
}).catch(/* reject() */function(err){
	console.log('countdown experienced an error ' + err.message);
});

출력 결과

5... 
4... 
3... 
2... 
1... 
countdown experienced an error ERROR!


동일하게 출격되는 것을 확인할 수 있습니다.

 

다음 포스팅에서는 프로미스 체이닝에 대해서 알아보도록 하겠습니다.

 

 

참고도서 : 러닝 자바스크립트

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

[JS]map(), reduce() 함수  (0) 2019.12.03
[JS]Promise (프라미스) - 2  (0) 2019.11.21
[JS]Ajax  (0) 2019.11.19
[JS]이벤트 버블링과 캡처링  (0) 2019.11.15
[JS]moment.js를 이용한 날짜 형식 다루기  (0) 2019.11.13
Comments