본문 바로가기
프로그래밍

프론트엔드 웹 서비스에서 우아하게 비동기 처리하기 (feat. Toss Slash 컨퍼런스)

by 자유코딩 2021. 7. 15.

문제가 있는 코드 예시

 

function fetchAccounts(callback) {
  fetchUserEntity((err, user) => {
    if(err) {
      callback(err, null);
      return;
    }
    fetchUserAccounts(user.no, (err, accounts) => {
      if(err) {
        callback(err, null);
        return;
      }
      
      callback(null, accounts);
    });
  });
}

안 좋은 이유 1. err , 성공 경우가 전혀 나뉘어있지 않다.

안 좋은 이유 2. 매번 비동기 호출을 할때마다 에러 처리를 해야한다.

 

좋은 코드로 바꾼 예

async function fetchAccounts() {
  const user = await fetchUserEntity();
  const accounts = await featchUserAccounts(user.no);
  return accounts;
}

좋은 이유 1. 성공하는 경우만 다루고, 실패하는 경우는 catch 절에서 분리해서 처리한다.

좋은 이유 2. 실패하는 경우에 대한 처리를 위임할 수 있다.

 

외부의 호출하는 쪽에서 try-catch 해도 되고, 필요하다면 내부에서 try-catch 해도 된다.

 

좋은 코드의 특징

     성공하는 경우 / 실패하는 경우를 나눠서 처리한다.

 

안 좋은 코드의 특징

    성공 / 실패 경우가 섞여있다.

 

컴포넌트에서 비동기적으로 데이터를 받아서 표시할때는 어땠는가

function Profile() {
  const foo = useAsyncValue(() => {
    return fetchFoo();
  });
  
  if(foo.error) return <div>로딩 실패</div>
  if(!foo.data) return <div>로딩중입니다.</div>
  return <div>{foo.data.name} 님 안녕하세요!</div>
}

이런 식으로 if 를 넣어서 했었다. 에러가 났을때 렌더링 하는 것을 계속 적어줘야 했다.

 

Suspense 를 쓰면 fallback에 에러가 있을때 렌더링할 컴포넌트를 정의할 수 있다.

 

function ProfilePage() {
  return (
    <Suspense fallback={<h1>Loading profile...</h1>}>
      <ProfileDetails />
      <Suspense fallback={<h1>Loading posts...</h1>}>
        <ProfileTimeline />
      </Suspense>
    </Suspense>
  );
}

 

이렇게 적어두고 ProfileTimeLine 컴포넌트를 렌더링하다 문제가 있다면 fallback 에 작성한 컴포넌트가 나온다.

 

try-catch로 감싼 async-await와 유사하다.

 

fallback에 대한 처리를 외부로 위임할 수 있게 되는 것이다.

 

아래와 같이 작성하면 앱 전체에 대해서 할 수도 있다.

 

 

댓글