[React] 콜백 함수/ Promise / async와 await

겨레·2024년 12월 4일

[React] 리액트 스터디

목록 보기
78/95

📍 콜백 함수(callback function)

  • 콜백 함수는 다른 함수의 인자로 전달되어 특정 이벤트가 발생하거나 작업이 완료된 후 호출되는 함수로 주로 비동기 작업에 사용된다.
  • 여러 번 순차적으로 처리하고 싶다면 콜백 함수를 중첩해 구현할 수 있는데, 가독성이 좋지 않아 지양한다.
  • 예시
// increase 함수 => 숫자에 10을 더하고, 1초 후 콜백 함수를 호출 
function increase(number, callback) {
  setTimeout(() => {
    const result = number + 10; // 10을 더한 결과 계산
    if (callback) {
      callback(result); // 결과를 콜백 함수로 전달
    }
  }, 1000); // 1초 후에 실행
}

// increase 함수 호출 후 1초 후 결과 출력
increase(0, result => {
  console.log(result); // 출력: 10
});

📍 Promise

  • JavaScript에서 비동기 작업을 처리하는 객체로, 비동기적인 코드 실행의 결과를 다루기 쉽게 해주기 위해 ES6에 도입된 기능이다.
  • Promise는 비동기 작업이 완료 또는 실패했을 때의 결과를 나중에 사용할 수 있게 해준다. 이를 통해 콜백 지옥(callback hell) 같은 복잡한 코드를 피할 수 있다.

📍 Promise 객체의 상태와 메서드

  • ① Promise 상태 (Pending, Resolved, Rejected)
    비동기 작업의 상태를 나타내는 세 가지 상태

    ✔ Pending
    : 비동기 작업이 아직 완료되지 않은 상태로 resolve나 reject가 호출될 때까지 기다림.

    ✔ Resolved
    : 비동기 작업이 성공적으로 완료된 상태로 Promise가 처리된 결과를 반환함.

    ✔ Rejected
    : 비동기 작업이 실패한 상태로 Promise가 실패 이유나 에러를 반환함.


  • ② Promise 메서드 (resolve, reject, then, catch, Promise 체이닝)
    Promise를 사용하여 비동기 작업을 처리할 때 사용되는 메서드

    ✔ resolve
    비동기 작업이 성공적으로 완료되었을 때 호출됨.
    이때 resolve가 전달하는 값은 .then()에서 사용할 수 있음.

    ✔ reject
    비동기 작업이 실패했을 때 호출되어 에러를 반환함.
    이때 reject는 에러 메시지나 실패 이유를 전달하고, 실패 이유는 .catch()에서 처리할 수 있음.

    ✔ then
    Promise가 성공적으로 완료된 후 실행할 콜백 함수를 정의함.
    resolve가 호출되면, 그 결과를 .then()에서 다룰 수 있음.

    ✔ catch
    Promise가 실패한 경우 실행할 콜백 함수를 정의함.
    reject가 호출되면, 그 에러를 .catch()에서 처리함.

    ✔ Promise 체이닝
    여러 비동기 작업을 순차적으로 처리할 때 사용됨.
    then 메서드를 이어서 호출해 비동기 작업들을 순차적으로 처리할 수 있음.
  • 예시1
// increase 함수는 숫자에 10을 더하고 Promise를 반환
function increase(number) {
  return new Promise((resolve) => {
    setTimeout(() => {
      const result = number + 10; // 10을 더한 결과 계산
      resolve(result); // Promise를 해결하고 결과 반환
    }, 1000); // 1초 후에 실행
  });
}

// 비동기 함수 main을 정의하여 await로 increase 함수의 완료를 기다림
async function main() {
  const result = await increase(0); // increase 함수 호출 후 1초 기다림
  console.log(result); // 출력: 10
}

// main 함수 호출
main();

  • 예시2
    여러 작업을 연달아 처리한다고 해서 함수를 여러 번 감싸는 것이 아니라 .then을 사용해 그다음 작업을 설정하기 때문에 콜백 지옥이 형성되지 않는다.

    • 콜백 지옥

      // 콜백 지옥 예제 (콜백이 중첩됨)
      doTask1(function(result1) {
      doTask2(result1, function(result2) {
       doTask3(result2, function(result3) {
         doTask4(result3, function(result4) {
           console.log('최종 결과: ', result4);
         });
       });
      });
      });
    • promise 사용한 개선

      // Promise를 사용하여 콜백 지옥을 피하는 예제
      function doTask1() {
      return new Promise((resolve) => {
       setTimeout(() => resolve('결과1'), 1000);
      });
      }
      
      function doTask2(input) {
      return new Promise((resolve) => {
       setTimeout(() => resolve(input + ' -> 결과2'), 1000);
      });
      }
      
      function doTask3(input) {
      return new Promise((resolve) => {
       setTimeout(() => resolve(input + ' -> 결과3'), 1000);
      });
      }
      
      function doTask4(input) {
      return new Promise((resolve) => {
       setTimeout(() => resolve(input + ' -> 결과4'), 1000);
      });
      }
      
      // Promise 체이닝을 이용한 비동기 작업 처리
      doTask1()
      .then(result1 => {
       return doTask2(result1);  // 첫 번째 작업이 끝난 후 두 번째 작업
      })
      .then(result2 => {
       return doTask3(result2);  // 두 번째 작업이 끝난 후 세 번째 작업
      })
      .then(result3 => {
       return doTask4(result3);  // 세 번째 작업이 끝난 후 네 번째 작업
      })
      .then(finalResult => {
       console.log('최종 결과:', finalResult);  // 모든 작업 완료 후 최종 결과 출력
      })
      .catch(error => {
       console.error('에러 발생:', error);
      });

📍 async와 await

  • JavaScript에서 비동기 작업을 더 쉽게 다루기 위해 ES2017(ES8)에서 도입된 기능
  • React에서도 비동기 작업(예: API 호출, 데이터 처리 등)을 처리할 때 async와 await를 사용해 코드의 가독성을 높이고, Promise를 처리하는 방식이 더 간결하고 직관적이게 된다.

  • async 함수 ⇒ 함수 앞에 붙여서 비동기 함수임을 명시하는 키워드
    • async로 선언된 함수는 항상 Promise를 반환

  • await 키워드 ⇒ Promise가 처리될 때까지 기다리게 하는 키워드
    • async 함수 내에서만 사용할 수 있음.
    • Promise가 해결되거나 거부될 때까지 함수의 실행을 일시 정지시키고, Promise가 해결되면 그 값을 반환함.

📍 기본 사용법

// 예시
// 비동기 함수 선언
async function fetchData() {
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();
  return data;
}
  • 예시
import React, { useState, useEffect } from 'react';

const FetchDataComponent = () => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  // 비동기 함수로 데이터 호출
  const fetchData = async () => {
    try {
      const response = await fetch('https://api.example.com/data');
      if (!response.ok) {
        throw new Error('Network response was not ok');
      }
      const data = await response.json();
      setData(data);
    } catch (error) {
      setError(error.message);
    } finally {
      setLoading(false);
    }
  };

  // 컴포넌트가 마운트되면 데이터 요청
  useEffect(() => {
    fetchData();
  }, []);  // 빈 배열로 한 번만 실행되게 설정

  if (loading) {
    return <div>Loading...</div>;
  }

  if (error) {
    return <div>Error: {error}</div>;
  }

  return (
    <div>
      <h1>Data:</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
};

export default FetchDataComponent;
profile
호떡 신문지에서 개발자로 환생

0개의 댓글