프로미스(Promise)

라용·2022년 8월 12일
0

인프런 강의 자바스크립트 중급 - 코딩앙마 를 듣고 정리한 내용입니다.

Promise 를 사용하면 뭔가를 요청할 때 동작 여부를 알려달라고 하고 자리를 비울 수 있습니다. 아래처럼 작성합니다.

const pr = new Promise((resolve, reject) => {})
// resolve 는 성공했을 때 실행하는 함수
// reject 는 실패했을 때 실행하는 함수

이렇게 어떤 일이 완료되었을 때 실행하는 함수를 callback 함수라고 합니다. 동작 원리에 따라 stateresult 변화를 살펴보면,

// new Promise 상태에서는
state : pending(대기)
result : undefined

// resolve(value) (동작이 성공하면)
state : fulfilled(이행됨)
result : value

// reject(error) (동작이 안되면)
state : rejected(거부됨)
result : error

예를 들어

const pr = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('OK')
	}, 3000)
});

위 코드를 실행한다면 statepending 이었다가 3초 후에 fullfilled 가 되고, result 에 'OK' 가 들어갑니다.

이제 생산자가 아닌 소비자의 코드를 작성해보면,

const pr = new Promise((resolve, reject) => {
	setTimeout(() => {
		resolve('OK')
	}, 3000)
});

pr.then(
	function(result){}, // 이행 되었을 때 실행
	function(err){} // 거부 되었을 때 실행
);
// 위에 생산자가 resolve 로 실행되어서 두번째 콜백 err 는 실행되지 않는 상태

then 이외에 catchfinally 를 사용할 수 있습니다. catch 는 에러가 난 경우에만 실행하게 할 수 있습니다.

// 기존 코드
pr.then(
	function(result){}, // 이행 되었을 때 실행
	function(err){} // 거부 되었을 때 실행
);

// 위 코드를 아래처럼 수정 가능,
// 가독성도 좋고, 첫번째 함수를 실행하지 못했을 때 나는 에러도 잡아준다.  

pr.then(
	function(result){}
).catch(
	function(err){} 
);

finally 는 이행이든 거부든 처리가 완료되면 항상 실행됩니다. 로딩 화면 같은 것을 없앨 때 유용합니다.

pr.then(
	function(result){}
).catch(
	function(err){}
).finally(
	function() {
		console.log("실행 끝")
	}
)

총 3개의 상품을 주문하는 예제가 있을 때,

const f1 = (callback) => {
	setTimeout(function() {
		console.log("1번 주문 완료");
		callback();
	}, 1000);
}
const f2 = (callback) => {
	setTimeout(function() {
		console.log("2번 주문 완료");
		callback();
	}, 3000);
}
const f3 = (callback) => {
	setTimeout(function() {
		console.log("3번 주문 완료");
		callback();
	}, 2000);
}

promise 를 사용하지 않고 함수 3개를 실행하는 코드를 작성하면 함수를 인자로 받기 때문에 아래와 같이 뎁스가 깊어집니다.

console.log('시작')
f1(function(){ // 콜백 함수를 인자로 받으므로 () 안에 function 
	f2(function(){ // f1 다음에 f2 가 실행되므로
		f3(function(){ // f2 다음에 f3 이 실행되므로
			console.log('끝'); 
		})
	})
})

위 코드를 promise 를 써서 표현해보면,

// 우선 기존 주문 코드 수정
const f1 = () => {
	return new Promise((res, rej) => {
		setTimeout(() => {
			res("1번 주문 완료");
		}, 1000);
	});
};
const f2 = (message) => {
	console.log(message);
	return new Promise((res, rej) => {
		setTimeout(() => {
			res("1번 주문 완료");
		}, 3000);
	});
};
const f3 = (message) => {
	console.log(message);
	return new Promise((res, rej) => {
		setTimeout(() => {
			res("3번 주문 완료");
		}, 2000);
	});
};

// 실행 코드
console.log("시작");
f1()
	.then((res) => f2(res)) 
	.then((res) => f3(res)) 
	.then((res) => console.log(res))
	.catch(console.log)
	.finally(() => {
		console.log("끝");
	});

이렇게 프로미스가 연결, 연결 되는 것을 프로미스 체이닝 Promise Chaining 이라고 합니다. 현재 각 제품은 1초, 2초, 3초가 걸려서 총 6초가 걸립니다. 만약 3개 제품을 동시에 주문한다면 3초면 해결이 됩니다. 이럴 때 Promise.all 을 사용합니다.

Promise.all([f1(), f2(), f3()]).then((res) => { // 배열로 함수를 담아서.
	console.log(res); // 값을 받아서 찍어준다.
})

3개 함수가 모두 완료되어야 then 이 실행되는 점을 유의합니다. 시간을 확인해보면,

console.time("x");  // 시간 재는 함수, timeEnd 까지 시간 3초.
Promise.all([f1(), f2(), f3()]).then((res) => { 
	console.log(res); 
	console.timeEnd("x");
})

Promise.all 은 하나의 정보만 누락되어도 에러가 뜹니다. 다 보여주거나 아에 안 보여줄 때 사용합니다. Promise.raceall 과 비슷하지만 경주의 느낌으로 하나라도 1등으로 완료되면 실행을 멈춥니다. 기존 코드에 적용하면 1초짜리 주문만 실행하고 멈춥니다.

console.time("x");  
Promise.race([f1(), f2(), f3()]).then((res) => {  // all 을 race 로 수정
	console.log(res); 
	console.timeEnd("x");
})
profile
Today I Learned

0개의 댓글