본문 바로가기
JavaScript/기초

[JavaScript] 비동기 처리 (Axios, Promise, Fetch, Async/Await)

by 뿌비 2024. 10. 12.
728x90

비동기 처리란? 

  • 비동기 처리(asynchronous processing)는 프로그램이 작업을 수행하는 동안 다른 작업을 동시에 처리할 수 있는 방식이다.
  • 비동기 처리를 사용하면 프로그램이 특정 작업이 완료될 때까지 기다리지 않고 다른 작업을 계속 수행할 수 있다.

비동기 처리 방식

1.  Axios

정의  Axios는 JavaScript 라이브러리로, 웹 브라우저와 Node.js 환경에서 HTTP 요청을 쉽게 보내고 받을 수 있게 도와준다.
API와의 통신, 즉 데이터를 서버로 전송하거나 서버에서 데이터를 받아오는 작업을 간편하게 할 수 있도록 설계되었다.
용도 API 호출: 외부 API에서 데이터를 가져오거나, 외부 서버에 데이터를 전송할 때 사용한다.
데이터 전송: 사용자 입력 데이터나 파일을 서버로 전송하는 작업에 사용된다. 
데이터 수신: 서버에서 제공하는 데이터를 받아와서 사용자에게 보여주는 데 사용된다.
비동기 처리 방식 Axios는 비동기 처리를 위해 내부적으로 JavaScript의 Promise 객체를 사용한다.
장점 요청과 응답에 대한 인터셉터 지원
Axios는 요청을 보내기 전, 또는 응답을 받은 후에 특정 작업을 추가할 수 있는 인터셉터 기능을 제공한다.
예를 들어, 모든 요청에 공통된 헤더를 추가하거나, 응답 데이터를 처리하기 전에 변환할 수 있다.

JSON 데이터 자동 변환
Axios는 서버에서 JSON 형식의 데이터를 자동으로 JavaScript 객체로 변환해준다.
이를 통해 응답 데이터를 쉽게 다룰 수 있으며, 별도로 JSON.parse()를 호출할 필요가 없다.

다양한 설정이 용이
Axios는 요청에 대한 다양한 설정을 쉽게 할 수 있다.
타임아웃 설정, 요청 헤더 추가, 응답 형식 지정 등 여러 가지 옵션을 제공하여, 사용자가 원하는 대로 요청을 커스터마이즈할 수 있다.
단점 라이브러리 추가로 인한 번들 크기 증가
Axios를 사용하기 위해서는 해당 라이브러리를 프로젝트에 추가해야 한다. 이로 인해 최종적으로 번들 파일의 크기가 커질 수 있다.
라이브러리가 크면 웹 페이지의 로딩 속도에 영향을 줄 수 있으므로, 필요 없는 경우에는 다른 방법을 고려할 수도 있다.
// axios 예제 코드
import axios from 'axios';

// GET 요청
axios.get('https://api.example.com/data')
    .then(response => {
        // API에서 받은 응답 데이터 처리
        console.log('데이터:', response.data); 
    })
    .catch(error => {
        // 오류가 발생했을 경우 처리
        console.error('오류:', error); 
    });

// POST 요청
axios.post('https://api.example.com/data', { name: 'John' })
    .then(response => {
        // API에서 받은 응답 데이터 처리
        console.log('응답:', response.data); 
    })
    .catch(error => {
        // 오류가 발생했을 경우 처리
        console.error('오류:', error);
    });

2. Promise

정의  Promise는 JavaScript에서 비동기 작업의 완료 또는 실패를 나타내는 객체다.
비동기 작업이 끝났을 때 결과를 반환하거나 오류를 처리할 수 있는 방법을 제공 한다.
- 대기(pending): 작업이 아직 완료되지 않은 상태
- 이행(fulfilled): 작업이 성공적으로 완료된 상태로, 결과를 반환
- 거부(rejected): 작업이 실패한 상태로, 오류 정보를 반환
용도 비동기 작업의 결과를 다루기 위한 기본적인 방법으로, 여러 비동기 작업을 체이닝(연결)하여 사용할 수 있다.
비동기 처리 방식 JavaScript의 기본 비동기 처리 패턴으로 사용된다.
장점 * 콜백 지옥 이란 ? 전통적인 비동기 처리 방식은 콜백 함수를 중첩해서 사용하는 형태가 많은데 이렇듯 코드가 복잡하고 가독성이 떨어지는 현상을 말한다.

콜백 지옥 피하기

Promise를 사용하면 체이닝을 통해 가독성을 높이고 코드의 구조를 깔끔하게 유지할 수 있다.

체이닝(연결) 가능

.then() 메소드를 사용하여 결과를 처리하고, 여러 개의 비동기 작업을 순차적으로 실행할 수 있다.
단점 복잡한 오류 처리
.catch() 메소드를 통해 오류 처리를 수행할 수 있지만, 여러 단계의 Promise 체인이 있는 경우 오류가 발생할 수 있는 위치가 복잡해질 수 있다.
예를 들어, 중간에 발생한 오류가 최종 결과에 영향을 줄 수 있으며, 이를 모두 처리하기 위해서는 추가적인 로직이 필요할 수 있다.
// Promise 예제 코드
// 비동기 작업을 수행하는 함수
const fetchData = () => {
    // Promise 객체를 반환
    return new Promise((resolve, reject) => {
        // 2초 후에 결과를 반환하는 타임아웃 설정
        setTimeout(() => {
            const success = true; // 성공 여부 설정 
            if (success) {
                // 작업이 성공했을 때 resolve 호출(이 함수는 Promise의 상태를 fulfilled(이행)로 변경)
                resolve("데이터 로드 완료"); // 성공 시 결과 반환 (resolve에 넘긴 값은 then에서 사용됨)
            } else {
                // 작업이 실패했을 때 reject 호출(이 함수는 Promise의 상태를 rejected(거부)로 변경)
                reject("데이터 로드 실패"); // 실패 시 오류 메시지 반환 (reject에 넘긴 값은 catch에서 사용됨)
            }
        }, 2000); // 2000ms (2초) 후에 setTimeout의 콜백 함수 실행
    });
};

// fetchData 함수 호출
fetchData()
    .then(data => {
        // 성공적으로 데이터를 받았을 때 처리하는 부분
        console.log(data); // resolve에 넘긴 값인 "데이터 로드 완료"가 출력됨
    })
    .catch(error => {
        // 오류가 발생했을 경우 처리하는 부분
        console.error(error); // reject에 넘긴 값인 "데이터 로드 실패"가 출력됨
    });

3. Fetch

정의   Fetch는 웹 API를 사용하여 네트워크 요청을 수행하는 데 쓰이는 기본 JavaScript 함수이다.
이 함수는 브라우저에서 제공하는 기능으로, 외부 서버에서 데이터를 가져오거나 서버로 데이터를 전송할 수 있다.
용도 데이터를 가져오거나 서버에 전송하는 용도로 사용되며, 비동기 요청을 처리할 수 있다.
비동기 처리 방식 Fetch는 비동기 작업을 처리하기 위해 Promise를 반환한다.
장점 내장 API: Fetch는 JavaScript의 기본 기능으로, 별도의 라이브러리나 설치가 필요 없다.
모던한 문법: Promise를 사용하여 비동기 작업을 더 깔끔하게 처리할 수 있다.
단점 JSON 변환: 서버에서 받은 응답을 JSON 형태로 변환하는 과정을 직접 해줘야 한다. 예를 들어, response.json() 메소드를 사용해야 한다.
복잡한 오류 처리: 네트워크 요청이 실패한 경우(예: 404 Not Found 등)는 Promise를 rejected 상태로 변경하지만, HTTP 상태 코드가 4xx 또는 5xx인 경우에는 오류를 자동으로 처리하지 않기 때문에 수동으로 체크해줘야 할 필요가 있다.
// fetch 예제 코드
// GET 요청을 보내는 예제
fetch('https://api.example.com/data') 
    .then(response => {
        // 응답이 성공적인지 확인
        if (!response.ok) { // 응답 상태가 200 (성공)이 아닌 경우
            throw new Error('네트워크 오류'); // 네트워크 오류 발생
            // 위의 코드가 실행되면 catch 블록으로 이동
        }
        return response.json(); // 응답 데이터가 성공인 경우 JSON으로 변환하여 다음 then으로 전달
    })
    .then(data => { // JSON 변환이 완료된 후 이 부분의 함수가 실행됨
        // 변환된 데이터 처리
        console.log('데이터:', data);
    })
    .catch(error => { 
        // 오류가 발생했을 경우 처리
        console.error('오류:', error); 
    });

// POST 요청을 보내는 예제
fetch('https://api.example.com/data', { 
    method: 'POST', // 요청 메소드 설정 (POST)
    headers: { // 요청 헤더 설정
        'Content-Type': 'application/json' // 요청의 데이터 형식을 JSON으로 지정
    },
    body: JSON.stringify({ name: 'John' }) // 보낼 데이터를 JSON 문자열로 변환하여 전송
})
    .then(response => { // 요청이 완료되면 이 부분의 함수가 실행됨
        // 응답이 성공적인지 확인
        if (!response.ok) { // 응답 상태가 200 (성공)이 아닌 경우
            throw new Error('네트워크 오류'); // 네트워크 오류 발생
            // 위의 코드가 실행되면 catch 블록으로 이동
        }
        return response.json(); // 응답 데이터가 성공인 경우 JSON으로 변환하여 다음 then으로 전달
    })
    .then(data => { // JSON 변환이 완료된 후 이 부분의 함수가 실행됨
        // 변환된 데이터 처리
        console.log('응답:', data); 
    })
    .catch(error => { // 오류가 발생했을 경우 이 부분의 함수가 실행됨
        // 오류가 발생했을 경우 처리
        console.error('오류:', error); 
    });

4. Async/Await

정의  Promise를 보다 간결하게 다루기 위한 문법으로, 이 문법을 사용하면 비동기 코드를 마치 동기 코드처럼 작성할 수 있어, 코드 흐름을 이해하기 쉽게 만들어 준다.
용도 비동기 작업을 쉽게 작성하고 가독성을 높이기 위해 사용된다.
비동기 처리 방식 내부적으로 Promise를 사용하여 비동기 작업을 처리한다.
async 키워드로 선언된 함수는 항상 Promise를 반환하며, await 키워드를 사용하여 Promise가 완료될 때까지 대기할 수 있다.
이 과정 덕분에 비동기 작업이 완료될 때까지 기다리는 방식으로 작성할 수 있다.
장점 코드가 더 간결해지고 이해하기 쉬워진다.
비동기 처리를 위해 여러 개의 then 메소드를 사용하는 대신, await를 통해 자연스러운 흐름으로 코드를 작성할 수 있다.
예를 들어, 데이터가 로드되는 과정이 순차적으로 진행되므로, 각 단계에서 데이터의 상태를 쉽게 추적할 수 있다
단점 Async/Await는 async로 선언된 함수 내에서만 사용할 수 있다.
즉, 이 문법을 사용하려면 반드시 async 키워드로 함수를 정의해야 한다.
또한, 비동기 작업의 결과는 반드시 await로 처리해야 하므로, 이 두 가지를 명심해야 한다.
// Async/Await 예제 코드
// 비동기 작업을 수행하는 함수
const fetchData = () => {
    // 새로운 Promise 객체를 반환
    return new Promise((resolve) => {
        // 2초 후에 결과를 반환하는 타임아웃 설정
        setTimeout(() => {
            // 2초가 경과한 후, 성공적으로 데이터가 로드되었다는 메시지를 resolve()로 반환
            resolve("데이터 로드 완료"); // 성공 시 결과 반환
        }, 2000); // 2000 밀리초 (2초)
    });
};

// 비동기 함수
const getData = async () => {
    try {
        // fetchData를 호출하고 결과를 기다림
        const data = await fetchData(); // fetchData 함수가 완료될 때까지 대기
        // 비동기 작업이 완료되면 결과를 data 변수에 저장
        console.log(data); // 데이터 출력 (예: "데이터 로드 완료")
    } catch (error) {
        // fetchData 호출 중 오류가 발생했을 경우 처리
        console.error('오류:', error); // 오류 메시지 출력
    }
};

// getData 호출
getData(); // getData 함수를 실행하여 비동기 작업 시작
728x90