JS 중급 | Promise

uoah·2023년 2월 9일
0

자바스크립트

목록 보기
31/33
post-thumbnail

🚀 오늘의 학습 목표

  • Promise
  • Promise 구문
  • catch / finally
  • 콜백 지옥 / 프로미스 체이닝(Promise Chaining)
  • Promise.all
  • Promise.race
  • console.time()

16. Promise

Promise 자바스크립트 비동기 처리에 사용되는 객체이다.

아래의 그림을 예시로 보자.

방법 1
1. 소비자가 상품을 상점에 주문
2. 소비자가 상품이 완료 되었는지 상점에 질문
-> 준비 되었다면 상품 차지
-> 준비 되지 않았다면 다시 질문
3. 준비 과정에서 실패가 발생할 수 있음 -> 다시 주문

소비자가 일정한 시간을 가지고 지속적으로 물어보는 것은 비효율적이다.
질문 중에 상품 제작에 실패하면 다시 상품을 주문해야 하는 번거로움도 생긴다.

방법 2
1. 소비자가 상품을 상점에 주문 -> 전화번호를 남김
2. 상점은 상품 제작 성공/실패 여부를 소비자에게 알린다.

상점에 주문을 하고 상품이 준비되었거나 실패됐을 때 알려 달라고 전화번호를 준다면,
상점에서 연락이 올 때까지 소비자는 다른 일을 할 수 있다.

방법 2프로미스(Promise) 라고 한다.

16.1. Promise 구문

const pr = new Promise((resolve, reject) => {
	// code
});
  • resolve : 성공
  • reject : 실패

📍 콜백 함수 (callvack function)

어떠한 일이 완료되고 난 뒤에 실행되는 함수

프로그래밍에서 콜백(callback) 또는 콜백 함수(callback function)는 다른 코드의 인수로서 넘겨주는 실행 가능한 코드를 말한다. 콜백을 넘겨받는 코드는 이 콜백을 필요에 따라 즉시 실행할 수도 있고, 아니면 나중에 실행할 수도 있다.


✅ Promise 의 3가지 상태

1. new Promise

const pr = new Promise((resolve, reject) => {
	// code
});

2. resolve(value)

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

3. reject(error)

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

3. 이행(resolve)/거부(rejected)시 실행하는 함수

pr.then(
  function(result){// 이행되었을 때 실행되는 code},	
  function(err){// 거부 되었을 때 실행되는 code}
)

이를 작성하여 보자.

pr.then(
  function(result){
    console.log(result + '가지러 가자');
  },
  function(err){
    console.log('다시 주문해 주세요');
  }
)

이 외에 catchfinally 이 있다.

3-1. catch

catch 는 에러가 발생한 경우, 즉 rejected 일 때만 사용 가능.
가독성이 더 좋고, 첫번째 함수 실행시 발생하는 에러도 잡아줄 수 있기 때문에 catch문을 사용하는 것이 좋다.

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

3-2. finally

finally 는 이행/거부 상관 없이 처리가 완료되면 실행된다.
로딩 화면 등을 없앨 때 유용하다.

pr.then(
  function(result){}
).catch(
  function(error){}
).finally(
  function(){
    console.log('---주문 끝---')
  }
)

🧑🏻‍💻 예제로 쉽게 이해하기

1. 이행(resolve)시

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

console.log('시작');
pr.then((result)=>{
  console.log(result);
})
.catch((err)=>{
  console.log(err);
})
.finally(()=>{
  console.log('끝');
})
/*
"시작"  
// 1초 지나고 싱행
"ok"
"끝"
*/

2. 거부(rejected)시

const pr = new Promise((resolve,reject)=> {
  setTimeout(()=>{
    reject(new Error("err..."));
  },1000);
});

console.log('시작');

pr.then((result)=>{
  console.log(result);
})
.catch((err)=>{
  console.log(err);
})
.finally(()=>{
  console.log('끝');
});
/*
"시작"  
// 1초 지나고 싱행
Error: err....
"끝"
*/

resolve, rejected 여부와 상관 없이 finally 는 실행된다.


😈 콜백 지옥(Callback Hell)

promise 를 사용하지 않으면 콜백 헬(콜백 지옥)에 빠질 수 있다.
콜백 지옥은 비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제이다.
이러한 코드 구조는 가독성도 떨어지고 로직을 변경하기도 어렵다.

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);
};

console.log('시작');
f1(function(){
  f2(function(){
    f3(function(){
      console.log('끝');
    });
  });
});

😇 프로미스 체이닝(Promise Chaining)

위 코드를 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('2번 주문 완료');
    }, 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('끝');
  });

// result //
/*
"시작"
"1번 주문 완료"
"2번 주문 완료"
"3번 주문 완료"
"끝"
*/

❓ Promise.all : f2 가 오류일때

f2 가 오류일 때 f3 은 건너 뛰고 finally 함수가 실행된다.

const f1 = () => {
  return new Promise((res, rej) =>{
    setTimeout(() => {
    res('1번 주문 완료');
  }, 1000);
  });
};
  
const f2 = (message) => {
  console.log(message);
  return new Promise((res, rej) =>{
    setTimeout(() => {
      rej('error');
    }, 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('끝');
  });

// result //
/*
"시작"
"1번 주문 완료"
"error"
"끝"
/*

16.2. Promise.all

위의 예제 코드에서 Promise.all 로 바꾸어 보자.

한꺼번에 시작하여 모두 이행되면 값을 사용할 수 있다.

console.log('시작');
Promise.all([f1(), f2(), f3()]).then((res) => {
  console.log(res);
});

❓ Promise.all : f2 가 거부(rejected) 일 때

const f1 = () => {
  return new Promise((res, rej) =>{
    setTimeout(() => {
    res('1번 주문 완료');
  }, 1000);
  });
};
  
const f2 = (message) => {
  console.log(message);
  return new Promise((res, rej) =>{
    setTimeout(() => {
       rej(new Error('error'));
    }, 3000);
  });
};

const f3 = (message) => {
 console.log(message);
 return new Promise((res, rej) =>{
    setTimeout(() => {
      res('3번 주문 완료');
    }, 2000);
  });
};

Promise.all([f1(), f2(), f3()]).then((res) => {
  console.log(res);
});

promise 와 다르게 에러 메시지와 함께 모두 실행되지 않는다.
하나의 정보라도 누락되면 페이지를 보여 주면 안 되는 경우 주로 사용된다.


🔗 [MDN] Promise.all 공부하러 가기


16.4. Promise.race

하나라도 완료되면 끝낸다.
프로미스 중에 가장 먼저 완료된 것의 결과값으로 그대로 이행하거나 거부한다.

Promise.race([f1(), f2(), f3()]).then((res) => {
  console.log(res);
});

용량이 큰 이미지를 로딩하는데 그 중 하나라도 완료되면 그 이미지를 보여 줄 때 사용된다.


🔗 [MDN] Promise.race 공부하러 가기


16.3. console.time()

console.time() 메서드는 타이머를 시작해 작업이 얼마나 걸리는지 추적할 수 있다.

const f1 = () => {
  return new Promise((res, rej) =>{
    setTimeout(() => {
    res('1번 주문 완료');
  }, 1000);
  });
};
  
const f2 = (message) => {
  console.log(message);
  return new Promise((res, rej) =>{
    setTimeout(() => {
     res('2번 주문 완료');
    }, 3000);
  });
};

const f3 = (message) => {
 console.log(message);
 return new Promise((res, rej) =>{
    setTimeout(() => {
      res('3번 주문 완료');
    }, 2000);
  });
};

console.time('t');
Promise.all([f1(), f2(), f3()]).then((res) => {
  console.log(res);
  console.timeEnd('t');
});

0개의 댓글

관련 채용 정보