JS에서의 비동기 처리_2

Suxxzzy.log·2021년 12월 19일
0

JS 비동기

목록 보기
2/3

JS 비동기 처리의 꽃 async/await이 등장한 이유

지금까지 callback을 이용한 비동기 처리부터 이를 개선하는 방법인 promise까지 살펴보았다. callback을 이용하게 되면 기본적인 비동기 처리는 가능하였지만, 이것이 중첩(nested)될 경우 콜백 지옥(pyramid of doom) 문제, 유지보수의 어려움이 있었다. 그래서 등장한 것이 Promise 객체였다.
Promise 객체는 executor 함수를 인자로 받았고, 이 함수는 resolve와 reject이라는 콜백함수를 받는다. (이 각각의 함수는 그냥 콜백함수에서 성공 및 실패 함수와 대응이 된다) 따라서 단순히 콜백 함수만 이용해 비동기 처리를 할 때보다 함수 내에 작성하여야 하는 인자의 수가 줄어든다는 장점이 있었다. 이로 인해 코드의 가독성도 향상된다는 장점도 있었다.

Promise의 경우, chaining이 가능하였다. 하지만 이것도 일반 콜백함수를 여러 개 중첩하여 사용하는 경우처럼 유사한 문제가 발생할 수 있다.
예를 들어 다음과 같은 코드를 보자.

function apple(){
	return new Promise((resolve) => setTimeout(resolve('apple'),1000));
}

function banana(){
	return new Promise((resolve) => setTimeout(resolve('banana'),1000));
}

apple()//
.then(apple => {
  return banana().then(banana=> `${apple}+${banana}`) 
})

만일 여러 개의 Promise를 chaining 하고, 실행 중에 어떤 코드 라인에서 에러가 났다면, 하나하나씩 디버깅을 해 보는 것은 여간 어려운 게 아니다.
왜냐하면 Promise의 경우도 콜백처럼, 코드를 비동기적으로 작성하기 때문이다.(물론 Promise가 항상 나쁘다고는 볼 수 없다!)

이러한 이유로, 비동기적 로직을 동기적 로직처럼 보이게 해 주는 장치인 async/await가 등장하였다.

async/await, 도데체 넌 어떻길래 편하다는건데?

앞에서 async/await는 비동기적 로직을 동기적 로직처럼 보이게 해 준다고 했다. 우선, 어떻게 쓰는지 알아야 어떻게 동기적 로직처럼 보이게 해준다는지 알 테니, 기본적인 공식부터 알아보자.

async function 함수명(){
  await 비동기처리 메서드명()
}

기본적으로 await 키워드는 비동기처리 메서드가 반드시 Promise를 리턴해야 붙일 수 있다고 한다.
이 공식은 아래의 기존 promise 코드에 다음과 같이 적용을 할 수 있다.

//기존의 promise로 작성한 코드
function eatLater(){
  return new Promise((resolve) => resolve('hello pizza'))
}

//async/await로 개선한 코드
async function food(){
  await eatLater()
  return 'hello pizza'
}

async/await을 사용하게 되면 일반 함수를 쓰는 것처럼 정리가 된다. 즉 비동기적 구조에 대한 사고를 하지 않아도 되도록 만들어준다.
(사실 아직 잘 이해를 못했고 거의 외운 상태임ㅠㅠ)
일단 내 생각엔 겉보기로는 resolve또는 reject을 쓰지 않아도 되니 타이핑을 많이 안해도 될 것 같다는 거..? 좀 더 코드 자체가 간단해졌다는 게 장점이라고 본다.

mdn 문서에서 관련된 코드를 찾아보고, 다른 블로그들을 쭉 검색해보면서 알게 된 건 async/await가 가장 빛을 발하는 때는 Promise chaining을 정리할 때라고 한다.
mdn에서 가져온 코드로 살펴보자.

fetch('coffee.jpg')
.then(response => response.blob())
.then(myBlob => {
  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
})
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});

위 코드를 async/await로 고치면 다음과 같다.

async function myFetch() {
  let response = await fetch('coffee.jpg');
  let myBlob = await response.blob();

  let objectURL = URL.createObjectURL(myBlob);
  let image = document.createElement('img');
  image.src = objectURL;
  document.body.appendChild(image);
}

myFetch()
.catch(e => {
  console.log('There has been a problem with your fetch operation: ' + e.message);
});

위에서 보던 Promise chaining이 async/await에 의해 단순화된 것을 확인할 수 있다.

Promise에서는 then, catch, finally로 에러핸들링 했다면, async/await에서는?

promise에서 에러핸들링을 했듯이 async/await에서도 에러핸들링 방법이 존재하는데, try-catch를 이용한다고 한다. 정상적인 코드 실행은 try구문 안에서, 에러인 경우 catch구문에서 처리를 한다.

async function food(){
  try{
    await 비동기처리메서드()
  }catch{
    error => console.log(error)
  }
}
profile
몫을 다하는 사람

0개의 댓글