티스토리 뷰

1. 비동기(async) 통신의 필요성

동기(Sync) 통신에서는 모든 데이터를 한 번에 전송하고 처리해야 하지만, 비동기(Async) 통신필요한 데이터만을 독립적으로 처리할 수 있어, 효율적으로 데이터를 변경하고 업데이트할 수 있다. 
비동기 통신이 필요한 경우는 아래와 같다.

  • Web API* 요청 (서버에 데이터를 받아올 때)]
  • 파일 읽기 (서버에 파일을 읽어와야 할 때)
  • 파일 쓰기 (클라이언트 단에서 데이터를 생성할 때 )
  • 파일 수정 (클라이언트 단에서 데이터를 수정할 때 )
  • 파일 제거 (클라이언트 단에서 데이터를 제거할 때)
  • 암호화 / 복호화
  • 예약 작업 (특정 날짜와 시간에 작업을 수행할 때)
API란 Application Programming Interface의 약자로, 두 소프트웨어 시스템이 서로 상호작용할 수 있도록 도와주는 인터페이스.. 즉, API는 다른 프로그램이나 서비스와 데이터를 주고받거나 기능을 사용할 수 있게 해주는 규약이나 도구, 

Web API는 서버와 클라이언트가 HTTP를 통해 데이터를 주고받을 수 있게 해주는 인터페이스로, 클라이언트가 서버에 요청을 보내고 서버가 이에 대한 응답을 보내는 방식

REST API 

REST API는 웹에서 HTTP를 사용하여 데이터를 주고받기 위한 규약으로, 기본적으로 CRUD(Create, Read, Update, Delete) 기능을 제공한다. 또한 이러한 기능을 모두 충족하고 REST규칙을 엄격하게 지키는 API를 'RESTful API'라고 부른다. 
REST API는 상태를 저장하지 않는다. 따라서 각 요청마다 필요한 정보(POST, GET 등의 상태)를 명시적으로 전달해야 한다.


2.  비동기 통신 방법 AJAX vs fetch 

 

AJAX 

AJAXAsynchronous JavaScript and XML의 약자로, 웹 브라우저에서 비동기적인 HTTP 요청을 보내고 응답을 받을 수 있게 해주는 Web API이다.

const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.example.com/data', true); // 비동기 GET 요청
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.responseText); // 서버로부터 받은 응답
  }
};
xhr.send(); // 요청 전송

- 콜백 함수
위 코드와 같이, AJAX는 XMLHttpRequest 객체를 사용하여 서버와 비동기적으로 데이터를 주고받는다. readyState* 값에 따라 함수가 호출되어 요청이 처리되며, 서버로부터 받은 응답을 다룬다. 
이 때 여러 개의 XML요청을 순차적으로 호출하기 위해서는 콜백함수를 중첩된 구조로 사용해야하는데, 이는 비동기 통신을 할 때 요청이 순차적으로 이루어진다는 보장이 없기 때문이다. 
그러나 콜백 함수를 사용하면 요청이 중첩될 때마다 콜백 함수가 연쇄적으로 호출되어 콜백 지옥(callback hell)을 초래할 수 있다. 이러한 구조는 코드의 가독성을 떨어뜨리고, 유지보수 및 확장성을 어렵게 만들 수 있다.

//AJAX 콜백 지옥 예시

function makeRequest(url, callback) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
      callback(xhr.responseText);  // 응답을 처리
    }
  };
  xhr.send();  // 요청 보내기
}

//콜백 지옥 부분

makeRequest('https://api.example.com/data1', function(response1) {
  console.log('Data 1:', response1);
  makeRequest('https://api.example.com/data2', function(response2) {
    console.log('Data 2:', response2);
    makeRequest('https://api.example.com/data3', function(response3) {
      console.log('Data 3:', response3);
    });
  });
});
*[readyState]
// 0 : uninitialized
// 1 : loading
// 2 : loaded
// 3 : interactive
// 4 : complete  => 성공 | 실패

 
그렇다면 중첩되는 구조를 만들지 않고,  어떻게 비동기 통신을 순차적으로 실행할 수 있을까?


- 프라미스(Promise)
프라미스(Promise)는 비동기 작업의 결과값을 처리하는 객체로, 성공(resolve) 또는 실패(reject) 상태를 나중에 처리할 수 있게 해준다.

// makeRequest 함수 수정 (Promise 사용)
function makeRequest(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url, true);
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
          resolve(xhr.responseText); // 응답 처리
        } else {
          reject("Error: " + xhr.status); // 오류 처리
        }
      }
    };
    xhr.send(); // 요청 보내기
  });
}

// Promise를 사용한 순차적 요청
makeRequest("https://api.example.com/data1")
  .then((response1) => {
    console.log("Data 1:", response1);
    return makeRequest("https://api.example.com/data2"); // 두 번째 요청
  })
  .then((response2) => {
    console.log("Data 2:", response2);
    return makeRequest("https://api.example.com/data3"); // 세 번째 요청
  })
  .then((response3) => {
    console.log("Data 3:", response3);
  })
  .catch((error) => {
    console.error("Request failed", error);
  });

그러나 XHR 요청 방식은 프라미스(Promise)객체가 아닌 onreadyStatechange 함수로 계속 상태 변경을 처리하고 있고, 코드가 반복적이다. 또한 CORS 처리를 제대로 하기 위해서는 여러 복잡한 설정을 해야한다. 이러한 단점들을 해결한 비동기 통신 API가 바로 fetch()이다.


fetch 

fetch() 기본 문법은 다음과 같다.

let promise = fetch(url, [options])
  • url – 접근하고자 하는 URL
  • options – 선택 매개변수, method나 header 등을 지정할 수 있음
// fetch로 요청 보내기
function makeRequest(url) {
  return fetch(url)
    .then(response => {
      if (!response.ok) {
        throw new Error('Network response was not ok ' + response.statusText);
      }
      return response.json(); // JSON 데이터 반환
    });
}

// fetch를 사용한 순차적 요청
makeRequest("https://api.example.com/data1")
  .then((response1) => {
    console.log("Data 1:", response1);
    return makeRequest("https://api.example.com/data2"); // 두 번째 요청
  })
  .then((response2) => {
    console.log("Data 2:", response2);
    return makeRequest("https://api.example.com/data3"); // 세 번째 요청
  })
  .then((response3) => {
    console.log("Data 3:", response3);
  })
  .catch((error) => {
    console.error("Request failed", error);
  });

위 코드와 같이 fetch를 사용하면 response(응답객체)를 통해 코드를 간소화 할 수 있고,  fetch()자체가 프라미스를 반환하기 때문에 새로운 프라미스 객체를 만들 필요가 없다.
 
 
 
 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/10   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함