비동기 처리하기

rnrnrnr·2023년 1월 3일
0
post-thumbnail

순서가 보장되어 있지 않은 상황

  • 웹 브라우저가 서버에 요청을 보냈는데 서버의 응답만 기다리고 다른 유저 인터랙션에 반응하지 않는다면 그냥 멈춰있게 된다 대신 다른 작업을 하다가 서버의 응답이 돌아오면 할 일을 하도록 하는게 비동기 프로그래밍을 대표적으로 나타내는 모습 중 하나라고 생각합니다.

다루기 어려운 이유

이 코드의 문제점

function getBazFromX(x) {
  if(x === undefined) {
	  return undefined;
  }

  if(x.foo === undefined) {
    return undefined;
  }

  if(x.foo.bar === undefined){
    return undefined;
  }

  return x.foo.bar.baz;
}
  • 이 코드는 x.foo.bar.baz에 안전하게 접근 할려고 하는 코드 이다.

이 함수가 하는 일이 명확하게 들어나기 보다는 명령어의 노이즈가 많아서 함수가 어떤 역할을 하는지 명확하게 드러나지 않는다고 생각합니다.

Optional Chaining

ECMAScript에 추가된 Optional Chaining문법을 활용 한 함수

function getBazFromX(x){
  return x?.foo?.bar?.baz;
}

이 함수는 함수가 하는 일을 흐리게 만들던 if문들이 사라져서 코드가 간결합니다. 어떤 역할의 함수인지 한눈에 확인이 가능합니다.

async await

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

이 함수는 성공하는 경우들만 모아서 살펴볼 수 있다는 점이 함수가 무엇을 하는 함수인지 간결하게 나타낸다

좋은 코드의 특징

  • 성공하는 경우와 실패하는 경우를 분리해서 처리한다.
  • 비즈니스 로직을 한눈에 파악할 수 있다
    - 함수가 무슨 용도인지를 파악하기 쉽다

어려운 코드의 특징

  • 실패, 성공의 경우가 서로 섞여 처리된다
  • 함수의 크기가 커지고 명시적으로 들어나지 못한다

비동기 코드 지옥

function Profile() {
  const foo = useAsyncValue(() => {
    return fetchFoo();
  });

  const bar = useAsyncValue(() => {
    if (foo.error || !foo.data) {
      return undefined;
    }
    return fetchBar(foo.data);
  });

  if(foo.error || bar.error) return <div>로딩 실패</div>
  if(!foo.error || !bar.error) return <div>로딩 중</div>
  return /* foo와 bar로 적합한 처리 */
}

bar를 가져오기 위해서는 foo가 있어야 되는 상황이다.

2개의 비동기 리소스를 가져올 때의 상태

로딩 중 / 에러 / 완료 3가지의 상태를 가지고 있습니다 만약에 2개의 비동기 작업이 있다면 9가지의 상태를 가지고 있습니다.

그렇다면 비동기 호출이 3개 4개가 된다면 더욱 복잡해 집니다.

비동기 코드지옥 해결

async function fetchFooBar() {
  const foo = await fetchFoo();
  const bar = await fetchBar(foo);
  return bar;
}

위에서 말한 성공에만 집중해 복잡도를 낮추고 일반적으로 작성하는 동기 로직과 큰 차이가 없습니다.

React의 비동기 처리는 어렵다

성공하는 경우에만 집중해 커모넌트를 구성하기 어렵고, 2개 이상의 비동기 로직이 개입할 때, 비즈니스 로직을 파악하기 점점 어려워진다

에러 상태와 로딩 상태 분리

  • 컴포넌트 쓰는 쪽 에서 로딩 처리와 에러를 처리한다
  • 로딩 상태는 Suspense의 Fallback으로 처리한다

Suspense

<Suspense fallback={<Spinner />}>
  <UserList />
</Suspense>

suspense로 감싸면 컴포넌트의 랜더링을 특정 작업 이후로 미루고, 그 작업이 끝날 때 까지는 fallback 속성으로 넘긴 컴포넌트를 대신 보여줄 수 있습니다.

profile
rnrnrnr

0개의 댓글