리액트

리액트 - Async&Await&Promise

개발자 포비 2024. 12. 23. 22:59

Async/Await/Promise 정리

1. 기본 개념

Promise

  • 비동기 작업의 결과를 담는 객체
  • 상태: pending(대기) -> fulfilled(성공) 또는 rejected(실패)
  • 체이닝으로 연속 작업 가능

async/await

  • async: Promise를 반환하는 비동기 함수 선언
  • await: Promise 완료까지 대기
  • try-catch로 에러 처리

2. 실행 패턴

순차 실행

  • await로 순서 보장이 필요한 작업 처리
  • 예) 질문 조회 후 답변 목록 조회

병렬 실행

  • Promise.all()로 독립적인 작업 동시 실행
  • 예) 프로필과 작성 글 목록 동시 조회

혼합 실행

  • 순차 실행과 병렬 실행 조합
  • 예) 질문 조회 후 답변/댓글 동시 조회

3. Promise 메서드

기본 메서드

  • .then() - 성공 처리
  • .catch() - 에러 처리
  • .finally() - 완료 처리

정적 메서드

  • Promise.all() - 모든 Promise 완료 대기
  • Promise.race() - 가장 빠른 Promise 완료 대기
  • Promise.allSettled() - 성공/실패 무관 완료 대기

4. 에러 처리

async/await 방식

try {
  await 비동기작업();
} catch (error) {
  에러처리();
}

Promise 방식

비동기작업()
  .then(성공처리)
  .catch(에러처리)

5. 주의사항

  • useEffect에서는 내부 async 함수 선언 후 호출
  • 조건부 실행 시 early return 활용
  • 불필요한 중첩 피하기

6. 선택 기준

async/await 선택

  • 복잡한 비동기 로직
  • 명확한 에러 처리 필요
  • 순차 실행이 많은 경우

Promise 체이닝 선택

  • 단순한 연속 작업
  • 함수형 프로그래밍 스타일
  • 메서드 체이닝이 자연스러운 경우

7. 실제 사용 예시 통합 코드

const ExampleComponent = () => {
  const [data, setData] = useState({ profile: null, questions: [], answers: [] });
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // 1. 순차 실행 예시 (답변 작성 후 댓글 조회)
  const handleAnswer = async (answerId, content) => {
    try {
      const response = await api.post(`/api/v1/answers/${answerId}`, { content });
      const comments = await api.get(`/api/v1/answers/${response.data.id}/comments`);
      return { answer: response.data, comments: comments.data };
    } catch (error) {
      throw new Error('답변 작성 중 오류가 발생했습니다.');
    }
  };

  // 2. 병렬 실행 예시 (프로필과 활동 내역 동시 조회)
  const loadUserData = async (userId) => {
    try {
      const [profile, questions, answers] = await Promise.all([
        api.get(`/api/v1/users/${userId}/profile`),
        api.get(`/api/v1/users/${userId}/questions`),
        api.get(`/api/v1/users/${userId}/answers`)
      ]);
      setData({
        profile: profile.data,
        questions: questions.data,
        answers: answers.data
      });
    } catch (error) {
      setError('사용자 데이터를 불러오는데 실패했습니다.');
    }
  };

  // useEffect 사용 예시
  useEffect(() => {
    const init = async () => {
      setLoading(true);
      try {
        await loadUserData(userId);
      } catch (error) {
        setError(error.message);
      } finally {
        setLoading(false);
      }
    };

    init();
  }, [userId]);

  if (loading) return <div>로딩중...</div>;
  if (error) return <div>{error}</div>;

  return (
    <div>
      {/* 컴포넌트 렌더링 로직 */}
    </div>
  );
};

export default ExampleComponent;