백앤드/Node.js

[포스코x코딩온] 웹개발자 입문 과정 5주차 | 콜백함수, Promise

영최 2023. 3. 28. 14:02
728x90

1. 비동기 방식이란

- 동기방식:

'순차적'으로 동작하는 방식

요청을 보낸 후 응답을 받아야 다음 동작 실행

- 비동기 방식:

'비'순차적 방식

요청을 보낸 후 응답에 관계없이 바로 다음 동작 실행

- 왜 비동기 방식을 써야하는가?:

동기 방식을 사용하면 서버가 언제 응답을 줄지 모르기때문에 계속 대기해야함

 

2. 비동기 '처리'가 필요한 이유

아래 코드를 돌려보자

function goMart() {
console.log("마트에 가서 어떤 음료를 살지 고민! ");
}
function pickDrink(){
setTimeout(()=>{
console.log("고민 끝");
product = "제로콜라";
price = 2000;
},1000)


function pay(product, price){
console.log(`상품명: ${product}, 가격:${price}`);
}
}


let product;
let price;
goMart();
pickDrink();
pay(product, price);
 
[출력 결과]
마트에 가서 어떤 음료 살지 고민!
상품명: undefined,가격:undefined
고민 끝
 
결과가 undefined로 나온다. 
이처럼 데이터 통신이 되기도 전에 값을 return해버리거나 이값을 이용하는 동작이 동시에 일어나면 
undefined값을 사용할 수 밖에 없다.
 
이를 방지하기 위해서 아래와 같은 3가지 방법을 사용해서 비동기를 처리한다.

3. 비동기 처리 방법 3가지

1) 콜백함수

- 콜백함수란?:

a. 다른 함수의 매개변수로 이용되는 함수

b. 어떤 이벤트에 의해 호출되는 함수 (다른말로는 다른 함수의 실행이 끝난 뒤 실행되는 함수)

 

위 코드를 콜백함수로 변경해보면 

function goMart() {
  console.log("마트에 가서 어떤 음료를 살지 고민! ");
}
function pickDrink(cb) { //매개변수로 콜백함수가 들어간다.
  setTimeout(() => {
    console.log("고민 끝");
    product = "제로콜라";
    price = 2000;
    cb(product, price); //콜백함수의 인자를 넣어준다. 여기서 콜백함수는 정의되지 않았다.
  }, 1000);
}
function pay(product, price) {
  console.log(`상품명: ${product}, 가격:${price}`);
}  // 콜백함수 정의

let product;
let price;
goMart();
pickDrink(pay); // 매개변수로 콜백함수를 넣어준다.

- 콜백 지옥:

콜백 함수가 반복되어 코드의 들여쓰기가 너무 깊어짐, 코드 가독성 및 유지보수성이 떨어짐 , 지양해야할 코드

 

콜백 지옥 예시 코드 (배경색을 순차적으로 변경하는 코드)

setTimeout(function () {
  document.querySelector("body").style.backgroundColor = "red";
  setTimeout(function () {
    document.querySelector("body").style.backgroundColor = "orange";
    setTimeout(function () {
      document.querySelector("body").style.backgroundColor = "yellow";
      setTimeout(function () {
        document.querySelector("body").style.backgroundColor = "green";
        setTimeout(function () {
          document.querySelector("body").style.backgroundColor = "blue";
        }, 1000);
      }, 1000);
    }, 1000);
  }, 1000);
}, 1000);

2) Promise 

- promise란?: 

콜백지옥 같은 코드를 해결하기 위한 방안으로 만든 객체이다.

promise는 성공시 resolve 함수를 호출하고 실패할 때는 reject 함수를 호출한다.

성공시 promise 뒤에 .then(...)을 사용해서 또 다른 작업을 수행할 수 있다.

실패시에는  promise 뒤에 .catch(...)를 사용해서 실패시 수행할 작업을 설정할 수 있다. 

 

- promise() 생성자:

promise 생성자는 주로 프로미스를 지원하지 않는 함수를 감쌀 때 사용한다.

 

아래와 같이 new Promise((resolve,reject)=>{}); 로 생성한다.

function fname() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve();
    }, 1000);
  });
}

 

위에서 작성한 콜백함수를 promise를 사용해서 비동기 처리해보면 코드는 아래와 같다.

function goMart() {
  console.log("마트에 가서 어떤 음료를 살지 고민! ");
}
function pickDrink() {
  return new Promise((resolve, reject) => {
    //Promise 생성자는 주로 프로미스를 지원하지 않는 함수를 감쌀 때 사용
    setTimeout(() => {
      console.log("고민 끝");
      product = "제로콜라";
      price = 2000;
      resolve();
    }, 1000);
  });
}
function pay() { // resolve() === pay()
  console.log(`상품명: ${product}, 가격:${price}`);
}

let product;
let price;
goMart();
pickDrink().then(pay);

    - promise 체이닝:

    콜백 지옥처럼 순차적으로 처리해야하는 비동기 작업이 여러개 있을 때 promise chaining을 이용해서 해결할 수 있다.

    return을 해주어 다음 .then(...)작업에 전달되도록 한다.

     

    위 코드에서 배경색을 순차 변경하는 콜백지옥을 promise chaining으로 변경해보면 다음과 같다.

    function colorChange(color) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          document.querySelector("body").style.backgroundColor = color;
          resolve();
        }, 500);
      });
    }
    colorChange("red")
      .then(() => {
        return colorChange("yellow");
      })
      .then(() => {
        return colorChange("orange");
      })
      .then(() => {
        return colorChange("green");
      })
      .then(() => {
        return colorChange("blue");
      });

     

    추가적인 promise chaining 예시코드는 아래와 같다.

    아래 코드는 (4 + 3)*2 -1 을 순차적으로 수행하는 코드이다.

    function add(n1, n2) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          let result = n1 + n2;
          resolve(result);
        }, 1000);
      });
    }
    
    function mul(n) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          let result = n * 2;
          resolve(result);
        }, 1000);
      });
    }
    
    function sub(n) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          let result = n - 1;
          resolve(result);
        }, 1000);
      });
    }
    
    add(4, 3)
      .then((result) => {
        console.log(result);
        return mul(result); //return 해야 다음 함수 매개변수로 넘어감
      })
      .then((result) => {
        console.log(result);
        return sub(result);
      })
      .then((result) => {
        console.log(result);
      });

     

    728x90