Javascript

비동기 프로그래밍 (feat. callback, Promise, async/await) 2부

마손리 2022. 12. 1. 16:56

1부에 이어서 비동기프로그래밍의 비교를 포스팅하겠습니다.

(1부: https://mason-lee.tistory.com/4)

 

callback

const first = (input, callback) => {
  callback(input);
};
const second = (input, callback) => {
  callback(input + "callback의 ");
};
const third = (input, callback) => {
  callback(input + "예제입니다.");
};

first("안녕하세요, ", (firstCallback) => {
  second(firstCallback, (secondCallback) => {
    third(secondCallback, (thirdCallback) => {
      console.log(thirdCallback);
    });
  });
});

callback함수는 굉장히 직관적입니다.

처음 콜백 함수를 정의해준뒤 callback으로 불러올 함수를 파라미터로 불러오면됩니다.

예시처럼 1개이상의 작업을 순차적으로 실행해야 할때에는 보시는 바와 같이 가독성이 너무 떨어지며 '콜백 지옥'이 펼쳐집니다.

 

Promise

const first = (input) => {
  return new Promise((resolve) => {
    resolve(input);
  });
};
const second = (input) => {
  return input + "Promise의 ";
};
const third = (input) => {
  return input + "예제입니다.";
};

first("안녕하세요, ")
  .then(second)
  .then(third)
  .then((result) => console.log(result));

Promise의 사용방법은 예제와 같습니다.

처음 함수에서 new Promise를 반환해준뒤 이후에 실행될 함수들을 정의해주고 처음 함수 이후 실행할 행동들을 .then을 이용하여 참조만 해주면 끝~ (.then을 사용하기 위해서는 최소 첫번째 함수만이라도 Promise가 반환되야 합니다.)

callback과 비교해보면 사용방법과 가독성이 훨씬 좋아졌습니다.

하지만 이게 다가 아닙니다.

 

const first = (input) => {
  return new Promise((resolve, reject) => {
    if (typeof input === "number") {
      reject("입력이 잘못되었습니다.");
    }
    resolve(input);
  });
};
const second = (input) => {
  return input + "Promise의 ";
};
const third = (input) => {
  return input + "예제입니다.";
};

first(1)
  .then(second)
  .then(third)
  .then((result) => console.log(result))
  .catch((result) => console.log(result));

Promise의 첫번째 예제에서 first 함수에 reject를 추가해준뒤 마지막 .then 이후에 .catch를 사용하여 에러 핸들링까지 완벽가능!

 

여기서 더??

Promise.resolve("안녕하세요, ")
    .then(second)
    .then(third)
    .then(console.log);

 

 

resolve상태만을 이용할때에는 first 함수를 지워주고 second와 third함수만을 정의해준뒤 위와 같이 Promise.resolve를 사용하여 간단히 만들어 줄수 있습니다.(Promise.reject().catch()의 형태 또한 사용이 가능합니다.)

 

async/await

const first = async (input) => {
  try {
    const secondResult = await second(input);
    const thirdResult = await third(secondResult);
    console.log(thirdResult);
  } catch (error) {
    console.log(error);
  }
};
const second = async (input) => {
  return input + "async/await의 ";
};
const third = async (input) => {
  return input + "예제입니다.";
};

first("안녕하세요, ");

Promise와 비교하였을때 사용방법은 다르지만 실행단계가 굉장히 비슷합니다.

간단하게 설명하자면 async는 Promise와 같고, awit = .then, try = resolve, catch = catch() 로 보시면 간단합니다.

참고로 async함수의 리턴값은 Promise형태를 반환합니다.

 

Promise와 async/await의 실제 예제

  const getAllProduct = async() => {
    const data = await fetch('/product')
    	.then(res=>res.json())
	productHandler(data)
  }

실제 데이터를 백엔드에서 가저올때 사용한 코드입니다.

async로 비동기 함수를 만들어준후 fetch를 이용해서 받아온 데이터를 .then을 이용하여 json형태를 오브젝트형태로 변형시켜줍니다. (참고로 fetch는 Promise로 반환되기 때문에 .then사용이 가능합니다. )

이후 fetch의 데이터를 await으로 기다려준후 productHandler라는 함수로 받은데이터를 보내줍니다.

만약 async함수를 사용하지않는다면 fetch뒤에 계속해서 .then이 붙어 줘야 했을겁니다. 하지만 위와 같이 Promise와 async 함수를 같이 사용하면 훨씬 쉽고 가독성이 좋은 형태로 코드를 짤수가 있게됩니다.