logo

Post

await vs return vs return await

게시글 대표 이미지

발단

일전에 기술 면접에서 이 포스트에서 다룰 내용에 대한 질문은 받은 적이 있다. async 키워드를 사용하며 크게 고민해본 적이 없어 약간 당황했었다. 그 자리에서 추론해가며 대답은 얼추했었는데, 면접관님의 추천으로 제대로 정리를 해보고자 한다.

개요

async 함수를 작성할 때 사용하는 await, return, return await의 차이점을 알고 상황에 맞게 올바른 키워드를 사용할 수 있어야 한다.

async function waitAndMaybeReject() {
  // Wait one second
  await new Promise((r) => setTimeout(r, 1000));
  // Toss a coin
  const isHeads = Boolean(Math.round(Math.random()));

  if (isHeads) return 'yay';
  throw Error('Boo!');
}

위 함수는 fulfill 되어 'yay'를 던져주거나 reject 되어 에러를 던지는 프로미스를 반환한다.

Just calling

async function foo() {
  try {
    waitAndMaybeReject();
  } catch (e) {
    return 'caught';
  }
}

foo를 호출하면 프로미스는 항상 undefined인 fulfilled 프로미스를 리턴한다.

waitAndMaybeReject()를 기다리거나(await 하거나) 리턴하지 않았기 때문이다. 개인적으론 첫 시작인 이 부분부터 헷갈렸다. 동시에 이 부분을 제대로 이해한다면 다음은 쉽다. 프로미스 객체의 상태에 대한 고민없이 무작정 코드를 쓰다 보면 놓치기 쉬운 부분인 것 같다.

Awaiting

async function foo() {
  try {
    await waitAndMaybeReject();
  } catch (e) {
    return 'caught';
  }
}

이번엔 1초를 기다린 뒤 undefined'caught'인 fulfilled 프로미스를 리턴한다.

waitAndMaybeReject()를 기다리기(await 하기) 때문에 해당 함수가 rejected 프로미스를 리턴하면 catch 블록이 실행되어 'caught'를 리턴하지만 fulfilled 프로미스를 리턴하면 await하기만 할 뿐이라 의도한 'yay' 값을 얻을 수는 없다.

Returning

async function foo() {
  try {
    return waitAndMaybeReject();
  } catch (e) {
    return 'caught';
  }
}

이번엔 1초를 기다린 뒤, 'yay'를 가진 fulfilled 프로미스 혹은 에러를 던지는 rejected 프로미스를 리턴한다.

다만 waitAndMaybeReject()를 기다리지(await 하지) 않고 바로 리턴하기 때문에 catch 블록이 실행되는 케이스는 없다.

Return-awaiting

try-catch 블록에서 필요한 것은 return await다.

async function foo() {
  try {
    return await waitAndMaybeReject();
  } catch (e) {
    return 'caught';
  }
}

이번엔 1초를 기다린 뒤 'yay' 혹은 'caught'를 가진 fulfilled 프로미스를 리턴한다.

다만 try/catch 구문이 아니라면 return await를 쓰는 것은 불필요한 중복이다. (async 함수는 함상 프로미스를 리턴하기 때문, ESLint에 관련 규칙도 존재한다.)

출처

await vs return vs return await

다른 글 읽기
이전 글
  • Cover Image for async/awiat는 언제나 옳은가?
      async/awiat는 언제나 옳은가?

      비동기 처리 함수는 일단 async/await 부터 쓰고 시작하시나요? 사실 그래도 되긴 합니다. 그래도 안써도 괜찮은 경우가 있는데 같이 알아보실?

    • 다음 글
    • Cover Image for 테스트 코드에서의 <Router> 에러와 다양한 Router 컴포넌트들
        테스트 코드에서의 <Router> 에러와 다양한 Router 컴포넌트들

        useHref() may be used only in the context of a <Router> component(feat. MemoryRouter)