Skip to main content

1.2 fetch()


1. 개요

한 마디로 JavaScript의 fetch() 메서드는 비동기 통신으로 요청(request)를 발행하고, 해당 응답(response)를 취득하는 함수이다.
Fetch API 라고 하는 창구를 통해 서버로 원하는 데이터 요청을 전송하면 response를 기다리면서 다른 처리도 가능하다.

  • 요청에 대한 응답을 받을 때까지 다음 처리를 유보하고 기다리는 것이 통기통신
  • 요청을 발행하고 응답을 받을 때까지 다른 처리를 할 수 있는 것이 비통기통신이다. → fetch()

평소 자주 볼 수 있는 비동기 통신의 대표적인 예시는 구글 서제스트이다.
페이지 전체 새로고침 없이 데이터 요청이 가능하며 사용자가 입력을 계속하는 동안에도 UI가 멈추지 않는다.
이건 사용자가 글자를 입력할 때마다 input이벤트가 발생하고 백그라운드에서 fetch로 요청을 하기 때문이다.
fetch가 성공하면 그럼 서버가 추천한 데이터를 then으로 처리해서 실시간으로 데이터를 바로 화면에 띄운다.

image.png



2. fetch() vs XMLHttpRequest

fetch("URL");

fetch가 나오기 전에는 AJAX라고 해서 XMLHttpRequest를 사용했다.
그냥 간단하게 GET요청을 하려면 최소 코드가 3줄이 된다.

const xhr = new XMLHttpRequest();      // 1. 객체 생성
xhr.open("GET", "https://example.com/data"); // 2. 요청 준비
xhr.onload = () => {                   // 3. 응답 처리
  if (xhr.status === 200) {
    console.log(JSON.parse(xhr.responseText));
  } else {
    console.error("에러 발생");
  }
};
xhr.send();                            // 요청 전송

fetch는 기본적으로 method를 따로 지정하지 않으면 GET 방식을 디폴트로 한다.

fetch("https://example.com/data") // GET 요청 (기본값)
  .then(response => {
    if (!response.ok) throw new Error("에러 발생"); // 상태 코드 체크
    return response.json(); // JSON 변환
  })
  .then(data => {
    console.log(data); // 서버에서 받은 데이터 출력
  })
  .catch(error => {
    console.error(error.message); // 오류 처리
  });

이것을 다시 async/await로 수정해 가독성을 높인 것이 바로 아래와 같다. 여러 fetch 요청을 await로 순차적으로 병렬처리 가능하다.

async function fetchData() {
  try {
    const response = await fetch("https://example.com/data"); // GET 요청
    if (!response.ok) throw new Error("에러 발생");           // 상태 코드 체크

    const data = await response.json();                       // JSON 변환
    console.log(data);                                        // 데이터 출력
  } catch (error) {
    console.error(error.message);                             // 오류 처리
  }
}

// 함수 호출
fetchData();

3. 반환값

fetch는 반환값이 Promise 객체이다.

Promise라는 것은 처리가 성공했는지 실패했는지 상태를 나타내는 객체로 그에 따른 예외처리를 컨트롤한다.
비동기로 행해지는 통신은 반드시 성공하는 것이 아니라 최종 처리 상태가 성공/실패 어느쪽이 될 지 모른다.

  • 성공시 후속 처리에서는 취득한 데이터를 어떻게 다룰지 지정하고
  • 실패한 경우 실패했음을 알리는 화면을 사용자에게 띄워야 함

즉, 데이터 취득을 하는 코드와 취득 후 처리 코드를 분산시키지 않고 하나로 관리하는 것이 바로 Promise객체이다.

성공한 경우 then(성공시 처리내용);
실패한 경우 catch(실패시 처리내용);
// 1. 사용자 정보 가져오기
fetch("https://example.com/user/123")
  .then(response => {
    if (!response.ok) throw new Error("사용자 정보를 가져올 수 없음");
    return response.json(); // JSON 변환
  })
  .then(user => {
    console.log("사용자 정보:", user);
    // 2. 사용자의 주문 내역 가져오기
    return fetch(`https://example.com/orders/${user.id}`);
  })
  .then(response => {
    if (!response.ok) throw new Error("주문 내역 가져오기 실패");
    return response.json();
  })
  .then(orders => {
    console.log("주문 내역:", orders);
    // 3. 주문 중 첫 번째 주문의 상세 정보 가져오기
    if (orders.length === 0) throw new Error("주문 내역이 없음");
    return fetch(`https://example.com/order-details/${orders[0].id}`);
  })
  .then(response => {
    if (!response.ok) throw new Error("주문 상세 정보 가져오기 실패");
    return response.json();
  })
  .then(orderDetails => {
    console.log("주문 상세 정보:", orderDetails);
  })
  .catch(error => {
    // 위의 단계 중 어디서든 오류 발생 시 여기서 처리
    console.error("에러 발생:", error.message);
  });