Home 토스 | 프론트엔드 웹 서비스에서 우아하게 비동기 처리하기
Post
Cancel

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


비동기 = 순서가 보장되지 않은 상황

대표적인 비동기 상황
서버에 요청을 하면 응답이 올 때 까지 기다리고 다른 유저 인터랙션에 반응할 수 없는 것이 아닌, 서버에서 응답이 올 때 까지 다른 작업을 하면서 응답이 오면 다시 이어서 할 일을 하는 것이다.

따라서 끊기지 않는 60프레임*의 좋은 사용자 경험을 위해서는 비동기 프로그래밍은 필수이다.

웹 브라우저 렌더링은 60프레임이다.
https://365kim.tistory.com/152
https://ordinary-code.tistory.com/58

좋은 코드란 무엇인지 예제를 통해 알아본 뒤 비동기 처리에 적용해보자

JS에 Promise가 없던 시절

JS에 Promise가 없었을 때의 코드를 보면 callback함수를 매개변수에 넣어서 callback을 구현한 것을 볼 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    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;
                }

                callback(null, accounts);
            });
        });
    }

위 예제 코드의 문제점
성공과 실패하는 경우가 같이 있어서 함수의 역할이 가려진다. 또 코드를 작성하는 입장에서 매번 비동기 호출을 할 때 마다 에러 처리를 해줘야해서 불편하다.


위의 코드를 보고 async-await로 구현된 코드를 보면 async-await의 좋은 점을 알 수 있다.

1
2
3
4
5
async function fetchAccounts(){
    const user = await fetchUserEntity();
    const accounts = await fetchUserAccounts(user.no);
    return accounts;
}

‘성공하는 경우’만 다루고 ‘실패하는 경우’는 catch절에서 분리해서 처리한다. 덕분에 함수의 역할이 잘 드러난다.
‘실패하는 경우’에 대한 처리를 외부에 위임할 수 있다.

이를 통해 좋은 코드의 특징을 정리할 수 있다.


좋은 코드 특징
성공/실패하는 경우를 분리해서 처리 가능
비즈니스 로직을 한눈에 파악이 가능

함수에 성공하는 경우만 적혀있어서 읽기도 쉽고 함수의 책임이 명확히 드러난다.


비동기 코드가 2개 이상일 때

비동기는 ‘로딩’, ‘에러’, ‘완료’ 총 3가지 상태가 존재한다.
예를 들어 2개의 비동기 리소스가 있다고 할 때 리소스를 가져올 떄의 상태를 나타낸 표가 있다.

 로딩에러완료
로딩🔺🔺
에러
완료🔺

그래서 비동기 리소스가 2개만 있다고 해도 총 9개의 상태를 가질 수 있다.

그런데 이러한 비동기 호출이 3, 4개면 더 복잡해질 것이다.


React의 비동기 처리는 어렵다.

React의 Hook이나 State를 사용하는 방식으로는 async-await와 같은 간단한 비동기 구현이 어렵다.

하지만 리액트 팀이 제안하는 “React Suspense for Data Fetching”이 있다.
말 그래도 “데이터를 가져오기 위한 Suspense” 이다. 취지는 async-await처럼 비동기 처리가 가능한 React 컴포넌트 구현이다.

성공한 경우와 로딩/에러의 경우를 나눠서 처리하면 에러/로딩 상태는 어떻게 처리할까? 함수의 에러처리를 감싸는 catch문에서 하는 것처럼 로딩상태와 에러처리도 컴포넌트를 쓰는 곳에서 해준다. 에러를 담당하는 <ErrorBoundary>, 로딩을 담당하는 <Suspense>가 있다. <runPureTask>라는 런타임은 비동기 함수도 동기적으로 작성할 수 있다.



후기

React를 설명하는 부분은 내가 react를 잘 몰라서 3번을 돌려봤을때도 잘 이해하기 어려웠다. 사실 Javascript callback 구문도 이해가 잘 안됐다.

This post is licensed under CC BY 4.0 by the author.

토스 | 실무에서 바로 쓰는 Frontend Clean Code

Pinia 공식문서 보고 적용하기