[FIFAPulse] 개발기록 - 지금까지 잘못 알고 있었던 비동기 처리에 대해

조민호·2023년 4월 25일
0

나중에 다른 게시글에도 비슷한 글이 올라가게 되겠지만.. 메인페이지에서 로그인 로직을 처리할 때 여러개의 비동기 처리를 동시에 진행해야 하는 상황이 있었다 여기에 전역 모달창과 함께 사용되는 useEffect의 렌더링 패턴과 종합해서 진행하려니까 아무 래도 기존에 비동기 처리 순서에 대해 다시 한번 공부가 필요했다

그러므로 여기다가는 내가 추가적으로 공부한, 내가 몰랐었던 비동기 처리 순서 내용들에 대해 작성해 보려 한다


비동기 코드의 동기적인 동작을 보장하기

“ fetch든 axios든 비동기 데이터를 가져오는 로직이 있고 , 이걸 사용하려는 모든 함수에 전부 다 async/await 을 사용해야 할까? “

사용하는게 맞다
이렇게 함으로써 비동기 코드의 동기적인 동작을 보장하는 것이기 때문이다


예시 1)
const getData = async () => {
  const data = await fetch('https://open.exchangerate-api.com/v6/latest');
  let result = await data.json(); // await한번 더 써야 함
  return result.rates;
};

**// 비동기로 받은 값을 사용해야 하므로 await을 사용**
const getRate1 = async (): Promise<object> => {
  const currency = await getData();
  return currency;
};

**// 비동기로 받은 값을 사용해야 하므로 await을 사용**
const getRate2 = async (): Promise<void> => {
  const rate: object = await getRate1();
};

getRate2();

예시 2) 중첩 구조인 경우도 마찬가지이다

예를 들어, 비동기 데이터를 가져오는 a함수가 있을 때

  • b함수가 a함수가 가져온 데이터값을 호출하고
  • c함수가 b함수가 받은 데이터값을 호출하고
  • d함수가 c함수가 받은 데이터값을 호출할 때

a,b,c,d 모두 다 await을 사용해야 하는 것이다



비동기 처리 순서



useEffect(() => {
    const getData = async () => {
      const fifa = new FIFAData();
      const result = await fifa.getUserId(nickNameInput);
      setUserInfo(result);
      console.log('1');
    };
    getData();
    console.log('2');
  }, [isLoggedIn]);

왜 이건 2 → 1 순으로 찍힐까?

  • 당연히 getData 는 async니까 비동기로써 2가 먼저 찍힘
  • 내가 헷갈렸던 것은 await이 있어야만 반드시 기다렸다가 진행하는 것인데 지금 await은 getData() 내부에 있다 단순히 외부에서는 async로 선언된 getData()만 있으므로 비동기처리가 되는 것이다



그렇다면 getData() 내부에서는 어떻게 될까?

useEffect(() => {
    const getData = async () => {
      const fifa = new FIFAData();
      console.log('1');
      const result = await fifa.getUserId(nickNameInput);
      console.log('2');
      setUserInfo(result);
    };
    getData();
  }, [isLoggedIn]);
  • async가 붙은 비동기 처리 함수인 getData() 내부에서는
  • 1이 먼저 찍히고
  • await을 기다렸다가
  • 2가 찍히는 것이다

이처럼 async가 getData()는 비동기 함수가 되므로

외부에서는 비동기적으로 실행이 되므로 다른 로직이 먼저 실행되고

그 다음 , 비동기 함수 내부가 실행이 될 때
해당 내부에서는 await이 진행될 때까지 기다리는 것이다



비동기 함수 내부는 어디까지 진행이 될까?


말 그대로 , 비동기 함수가 있으면 다른 외부 로직을 먼저 진행하는 건 맞는데 그렇다고
  • 비동기 함수 전체를 건너뛰는 것인가?
  • 아니면 비동기 함수의 await 전까지는 진행이 되는 것인가?

이 2개가 헷갈렸다
그래서 직접 실험을 해보니 아래와 같았다

// (1)
const getDataAndUpdateInfo = async () => {
	**// (2) 그래도 여기까진 우선 진행이 됩니다**
	const dbInfo = await getDocs(collection(dbService, 'userInfo'));
  // (4) 비동기 로직 진행
};
getDataAndUpdateInfo();

// (3) >> 기존에 진행중이던 외부 로직 (다른 useEffect , 다른 함수들 등...)

getDataAndUpdateInfo() 함수는 비동기 처리를 하는 함수이며

실제로 useEffect()든 아니면 다른 함수 안에서 위의 코드 부분이

실행되고 있다고 가정해보자

만약 getDocs라는 비동기 요청을 await과 함께 호출했을 때 ,

  • getDataAndUpdateInfo() 내부에서의 await로 지정한 비동기 동작들은 순서대로 진행이 되어야 하므로 await이 끝날 때까지 기다리다가 , 완료가 되면 그때 진행 되는 것이 맞다

그렇지만 , getDataAndUpdateInfo() 함수 외부의 다른 로직들은 기다리지 않는다

즉 ,기존에 진행중이던 다른 외부의 로직들이 있었다면

getDataAndUpdateInfo()가 async가 붙은 비동기 함수이므로

  1. `getDataAndUpdateInfo() 안에 await 전까지 먼저 진행`하다가

  2. await을 만나면 우선나머지 외부의 동작을 우선적으로 먼저 진행하게 되고

  3. 그 다음 이벤트 루프에 의해 테스크큐에 있던,

    `await 이후 부터` 실행이 되는 것이다

💡 외부 로직인 (3) 에서 상태값이 변경이 된다면
리렌더링 로직이 먼저 진행된 다음에 비동기 처리 로직 (4)가 진행된다
profile
웰시코기발바닥

0개의 댓글