인프런 강의 자바스크립트 중급 - 코딩앙마 를 듣고 정리한 내용입니다.
Promise
를 사용하면 뭔가를 요청할 때 동작 여부를 알려달라고 하고 자리를 비울 수 있습니다. 아래처럼 작성합니다.
const pr = new Promise((resolve, reject) => {})
// resolve 는 성공했을 때 실행하는 함수
// reject 는 실패했을 때 실행하는 함수
이렇게 어떤 일이 완료되었을 때 실행하는 함수를 callback
함수라고 합니다. 동작 원리에 따라 state
와 result
변화를 살펴보면,
// 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)
});
위 코드를 실행한다면 state
는 pending
이었다가 3초 후에 fullfilled
가 되고, result
에 'OK' 가 들어갑니다.
이제 생산자가 아닌 소비자의 코드를 작성해보면,
const pr = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK')
}, 3000)
});
pr.then(
function(result){}, // 이행 되었을 때 실행
function(err){} // 거부 되었을 때 실행
);
// 위에 생산자가 resolve 로 실행되어서 두번째 콜백 err 는 실행되지 않는 상태
then
이외에 catch
와 finally
를 사용할 수 있습니다. 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.race
는 all
과 비슷하지만 경주의 느낌으로 하나라도 1등으로 완료되면 실행을 멈춥니다. 기존 코드에 적용하면 1초짜리 주문만 실행하고 멈춥니다.
console.time("x");
Promise.race([f1(), f2(), f3()]).then((res) => { // all 을 race 로 수정
console.log(res);
console.timeEnd("x");
})