async와 await

오민영·2021년 7월 15일
0

Web API

목록 보기
9/9
post-thumbnail

자바스크립트의 비동기 처리 패턴 중 가장 최근에 나온 문법이다.
기존의 비동기 처리 방식인 callback함수와 Promise의 단점을 보완하고, 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다!

예시


// 일반 함수
function logName() {
	var user = fetchUser('domain.com/user/1');
	if(user.id === 1) {
		console.log(user.name)
	}
}

// 자바스크립트에서 비동기 처리 코드의 경우
// 콜백 함수 사용하면 코드의 실행 순서를 보장받을 수 있었다!
function logName() {
  // 아래의 user 변수는 위의 코드와 비교하기 위해 일부러 남겨놓았습니다.
  var user = fetchUser('domain.com/users/1', function(user) {
    if (user.id === 1) {
      console.log(user.name);
    }
  });
}

// async & await 추가
async function logName() {
  var user = await fetchUser('domain.com/users/1');
  if (user.id === 1) {
    console.log(user.name);
  }
}

async & await 기본 문법

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

예시

fetchIteims() 함수는 프로미스 객체를 반환하는 함수이다. fetchIteims() 함수를 실행하면, 프로미스가 이행(resolved)되며, 결과 값은 items 배열이 된다.

그리고, lotItems() 함수를 실행하면 fetchItems() 함수의 결과 값인 items 배열이 resultItems 변수에 담긴다. 따라서, 콘솔에는 [1, 2, 3]이 담긴다.

await를 사용하지 않았다면, 데이터를 받아온 시점에 콘솔을 출력하 수 있게 콜백 함수나, then()등을 사용해야 했을 것이다. 하지만 async await 문법을 사용함으로써 비동기에 대한 사고를 하지 않아도 되는 것이다.

function fetchItems(){
  return new Promise(function(resolve, reject){
    let items = [1, 2, 3];
    resolve(items);
  })
}

async function logItems(){
  let resultItems = await fetchItems();
  console.log(resultItems); // [1, 2, 3]
}          

async

async는 function 앞에 위치하고, async를 붙이면 해당 함수는 항상 Promise를 반환한다.

프라미스가 아닌 값을 반환하더라도 이행(성공) 상태의 프라미스(resolved promise)로 감싸 성공한 프라미스가 반환하하고, 명시적으로 프라미스를 반환하는 것도 가능하며 결과는 동일하다.

// 프라미스 반환 (1)
async function func(){
  return 1;
}

func().then(alert); // 1

// 명시적 프라미스 반환 (1)
async function f() {
  return Promise.resolve(1);
}

f().then(alert); // 1

await

await의 대상이 되는 비동기처리코드는 Axios등 프로미스를 반환하는 API 호출 함수이다.

await 함수는 Promise가 처리될 때까지 함수 실행을 기다리도록 해준다. 즉, Promise가 성공적으로 이행되면, 그 결과와 함께 실행이 재개되는 것이다.
그리고 awaitpromise.then보다 좀 더 깔끔하게 Promise의 result값을 얻을 수 있도록 해주는 문법이다.

예시

  • 자바스크립트는 await를 만나면, 프라미스가 처리될 때까지 기다리고, 결과를 그 이후에 반영한다.
  • 함수를 호출하고 함수 본문이 실행되는 도중에 (*)로 표시한 줄에서 잠시 중단되었다가, 프라미스가 성공적으로 이행되면 실행이 재개된다. 이 때 프라미스 객체의 result 값이 변수 result에 할당된다.
  • 따라서, 실행하면 1초 뒤에 완료가 출력된다.
async function func(){
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve('완료!'), 1000)
  })
  
  let result = await promise; // 위 Promise가 이행될 때까지 기다림 (*)
  
  alert(result); // 완료!
}

func();

일반함수엔 await를 사용할 수 없다!
async 함수가 아닌데, await를 사용하면 문법 에러가 발생한다.

실용 예제

아래 함수들을 실행하면 각각 사용자 정보와 할 일 정보가 담긴 프로미스 객체가 반환된다.

function fetchUser(){
  var url = 'https://jsonplaceholder.typicode.com/users/1'
  
  return fetch(url).then(function(response){
    return response.json();
  })
}

function fetchTodo(){
  let url = 'https://jsonplaceholder.typicode.com/todos/1';
  return fetch(url).then(function(response){
    return response.json()
  })
}                        

이 두 함수를 이용해서 할 일 제목을 출력해보자.

  1. fetchUser()를 이용해서 사용자 정보를 호출한다.
  2. 받아온 사용자 아이디가 1이면 할 일 정보를 출력한다.
  3. 받아올 할 일 정보의 제목을 콜솔에 출력한다.
async function logTodoTitle(){
  let user = await fetchUser();
  
  if(user.id === 1){
    let todo = await fetchTodo();
    console.lo(todo.title)
  }

에러 핸들링

프라미스가 정상적으로 이행되면, await promise 객체의 result에 저장된 값을 반환하지만, 프라미스가 거부되면, 마치 throw 문을 작성한 것처럼 에러가 던져진다.

async function func(){
  await Promise.reject(new Error("에러 발생"));
}

// 위 코드와 동일하다.
async function func(){
  throw new Error("에러 발생")
}

Promise에서 에러 처리를 위해 catch()를 사용했던 것처럼 async에는 catch {}를 사용하면 된다.

코드를 실행하다가 발생한 네트워크 통신 오류 뿐만 아니라, 간단한 타입 오류 등의 일반적인 오류까지도 catch로 잡아낼 수 있다. 발견된 에러는 error 객체에 담기기 때문에 에러의 유형에 맞게 에러코드를 처리하면 된다.

async function logTodoTitle(){
  try{
    let user = await fetchUser();
    
    if(user.id === 1){
      let todo = await fetchTodo();
      console.log(todo.title);
    }
  } catch(error){
    console.log(error)
  }
}

Reference

참고
참고

profile
이것저것 정리하는 공간

0개의 댓글