[TOSS SLASH 21] 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기

Gyuhan Park·2023년 9월 30일
0

conference

목록 보기
2/2

https://brand.toss.im/

[ 요약 ]
비즈니스 로직 한눈에 파악 가능
성공과 실패 코드 분리
성공하는 경우만 다루고 실패하는 경우는 외부에 위임
리액트는 ErrorBoundary 와 Suspense 로 로딩상태와 에러상태 분리 및 처리

📖 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기

토스 SLASH 21 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기

💭 좋은 코드란 무엇인가

📌 나쁜 코드 (1)

그냥 봐도 읽기가 어렵다.
x.foo.bar.baz 에 안전하게 접근하기 위한 목적에 비해 코드가 복잡하다.

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;
}

📌 좋은 코드 (1)

optional chaining 으로 문제를 해결할 수 있다.

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

읽기 쉬운 이유

  • 함수가 하는 일을 흐리는 if문 사라짐.
  • 함수의 역할 한눈에 파악 가능.

📌 나쁜 코드 (2)

성공하는 경우와 실패하는 경우가 섞여서 처리 -> 함수의 역할이 가려짐
비동기 처리할 때마다 에러체크 필요

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

📌 좋은 코드 (2)

async/await 으로 해결.

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

읽기 쉬운 이유

  • 성공하는 경우만 다루고 실패하는 경우는 분리하여 처리
  • 실패하는 경우는 외부에 위임

🗂️ 컴포넌트에서의 비동기 처리

컴포넌트에서 로딩과 에러 처리를 동시에 수행한다.

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

-> 성공하는 경우와 실패하는 경우가 섞여 있다.
-> 실패하는 경우에 대한 처리를 외부에 위임하기 어렵다.

📌 react suspense

  1. 성공한 경우에만 집중
  2. 로딩 상태와 에러 상태 분리
  3. 동기 코드와 유사하게 만듦
// Foobar.jsx
function Foobar() {
  const foo = useMemo(() => fetchFoo());
  const bar = useMemo(() => fetchBar(foo), [foo]);
  
  return <div>{foo}{bar}</div>;
}

// index.js
<ErrorBoundary fallback={<ErrorPage />}> // 에러상태
	<Suspense fallback={<Loader />}> // 로딩상태
		<Foobar />
	</Suspense>
</ErrorBoundary>

컴포넌트를 쓰는 쪽에서 로딩 처리와 에러 처리를 한다.
가장 가까운 Suspense의 fallback 으로 로딩 상태가 그려진다.
가장 가까운 ErrorBoundary가 componentDidCatch() 로 에러 상태를 처리한다.

모든 컴포넌트를 감싸는 것이 아니라 적당한 레벨 단위로 묶어준다.

💬 추가 키워드

react 18 에서 제공하는 기능
react에서 컴포넌트의 렌더 트리를 부분적으로 완성할 수 있다 -> UX 향상

  • react concurrent mode
  • useTransition
  • useDeferredValue
profile
단단한 프론트엔드 개발자가 되고 싶은

0개의 댓글