개념,기능 정리

비동기 처리-promise, async/await

rhdaud2 2024. 6. 10. 17:53

 

 

비동기 처리에 관한 개념 정리글을 작성한 적이 없는 것 같아 작성 시작

 

 


 

 

 

promise

 

promise는 비동기작업의 완료/실패를 처리하기 위해 사용되는 개념

(비동기 작업의 처리를 쉽게 하기 위해서 제작되었다)

 

비동기 작업이 끝난 이후 실행될 "콜백"을 등록할 수 있는 메서드를 제공하며

Promise 객체를 생성하기위해 "new Promise(프로미스 생성자)" 를 사용할 수 있다.

 

 

promise가 없을때의 발생 가능 문제점

- 콜백 함수의 중첩이 깊어져, 코드 이해와 유지보수가 어려워진다(콜백지옥)

- 에러 처리가 분산되어, 관리가 어렵고 흐름을 추적하기 힘들다

- 여러 비동기 작업을 순차적 혹은 병렬적 처리하는 경우 코드가 복잡해진다

 

=> 가독성 저하, 유지보수의 난이도 증가(복잡해지는 코드 진행)

 

 

promise의 3가지 상태

- 대기(pending)

- 이행(fulfilled)

- 거부(rejected)

 

 

promise 객체는  *then, *catch, *finally 등의 메서드로 이행 혹은 거부 이후의 동작을 정의해줄 수 있다.

*then: 처리 완료했을 때

*catch: 처리 실패했을때

*finally: 완료, 실패 여부에 상관 없이

 

 

 

(new Promise를 직접 사용해 비동기 처리 해본 적은 없기에 기록용으로 학습 자료를 가져왔다)

//생성 방법

const myPromise = new Promise((resolve, reject) => {
  // 비동기 작업을 수행합니다.
  if (/* 작업이 성공적으로 완료되면 */) {
    resolve("성공 메시지");
  } else {
    reject("실패 메시지");
  }
});

 

new Promise의 인자로는 resolve,reject를 받을 수 있다.

 

resolve 실행 : 수행에 성공했을 경우에 해당. pending을 fulfilled(이행 완료)로 바꾼다

reject 실행 : 수행에 실패했을 경우에 해당. pending을 rejected(이행 실패)로 바꾼다

 

//실 사용 예

const myPromise = new Promise((resolve, reject) => {
  setTimeout(() => {
    // 작업의 성공 여부를 나타내는 변수
    // 여기를 true <-> false 변경해가며 테스트해보세요!
    const success = true;

    if (success) {
      // resolve 함수 자체는 반환값이 없어요.
      // 다만, resolve 함수가 호출되면 그 값이 then 메서드의 callback 함수로 전달돼요.
      resolve("작업이 성공적으로 완료되었습니다!");
    } else {
      // 마찬가지 원리로, reject 함수가 호출되면 그 값이 catch 메서드의 callback 함수로 전달돼요.
      reject("작업이 실패했습니다.");
    }
  }, 2000); // 2초 후에 작업이 완료
});

myPromise
  .then((result) => {
    console.log(result); // "작업이 성공적으로 완료되었습니다!" 출력
  })
  .catch((error) => {
    console.log(error); // "작업이 실패했습니다." 출력
  });

 

myPromise라는 이름의 프로미스 생성 후,

 

myPromise.then / myPromise.catch로 정상 작동과 에러 처리

 

 


 

외부 api에 요청할때는 값을 직접적으로 가져오는 것이 아니라,

항상 promise를 반환하기 때문에 .then .catch 또는 async await를 이용하여 값에 접근한다

 

예시

 

 

 

 

 

 


 

 

 

 

 

여러 비동기 작업을 병렬로 처리하기(Promise.all)

 

Promise.all 메서드 사용시 모든 작업 완료까지 기다린 후 한번에 처리 가능(병렬 처리)

(Promise.all의 인자는 "배열"로 들어간다)

 

*순차 처리 : 1> 2> 3 처리 순서가 확실히 정해져야할 때의 처리

*병렬 처리 : 요청을 모두 보낸 후(동시에 시작한 후), 마지막 처리가 끝날 때 실행

=> 시간상으로는 병렬 처리가 큰 이점이 있기 때문에, 순서가 중요한 경우가 아닐 경우 병렬 처리 하는 것이 좋다

 

[ Promise.all 의 return 값 : promise ]

 

import React, { useState, useEffect } from "react";

function App() {
  const [data, setData] = useState({ posts: [], users: [] });

  useEffect(() => {
    // 두 개의 처리를 동시에 시작.
    Promise.all([
      fetch("https://jsonplaceholder.typicode.com/posts").then((response) =>
        response.json()
      ),
      fetch("https://jsonplaceholder.typicode.com/users").then((response) =>
        response.json()
      ),
    ])
    //배열로 2개의 프로미스가 반환되기때문에
    //0번 index는 posts, 1번 index는 users로 지정
      .then(([posts, users]) => {
        setData({ posts, users });
      })
      .catch((error) => console.error("데이터 펫칭 오류! => ", error));
  }, []);

 

 

 

 


 

 

promise 객체를 다루는 또 다른 방법, async/await

 

 

1. async 함수는 항상 promise 를 반환

2. await 키워드는 promise가 이행될 때까지 대기

 

=> 이를 이용해, "비동기 코드"를 "동기처럼" 작성 가능하기때문에 가독성이 향상된다

 

 

 

async/await의 장점

 

- 가독성 향상 (비동기 코드를 동기적으로 작성)

- try ... catch 구문을 사용한 간단한 에러 처리

 

 

 

예시 코드

function App() {
  const [post, setPost] = useState(null);

  useEffect(() => {
    const fetchPost = async () => {
      try {
        const response = await fetch(
          "https://jsonplaceholder.typicode.com/posts/1"
        );
        const data = await response.json();
        setPost(data);
      } catch (error) {
        console.error("Error fetching post:", error);
      }
    };

    fetchPost();
  }, []);

 

+) post가 있을 경우 띄우고, 아니면 로딩 띄우기 
 
 return <div>{post ? <div>{post.title}</div> : <div>Loading...</div>}</div>;
}

- 마운트 된 이후 데이터를 불러오기때문에 불러오는 동안 loading,,, 글자가 나오다가, 

정상적으로 불러오면 title 이 띄워짐

 

 

'개념,기능 정리' 카테고리의 다른 글

인증/인가 - 쿠키,세션,토큰,JWT  (1) 2024.06.11
Zustand  (1) 2024.06.11
Supabase  (0) 2024.05.30
memoization  (0) 2024.05.29
Yarn, Vite로 빌드 후 리액트 깃허브 배포하기  (0) 2024.05.29