-
🔍 비동기 데이터 통신
비동기 요청을 통해서 서버에서 데이터를 가져오는 것은 동적이고 상호작용적인 웹 애플리케이션에서 필수가 되었습니다.
이렇게 비동기 데이터 통신을 하는 방식으로는 XMLHTTPRequest 객체를 활용하는 것으로 수년 동안 사용한 방법입니다.
이후 Fetch API가 도입되어 비동기 요청 처리를 위한 더 간단한 접근 방식을 사용하게 되었습니다.
🌐 크롬 네트워크 탭
크롬의 네트워크 탭을 확인하면
xhr,fetchtype을 볼 수 있습니다.
🧩 XMLHttpRequest
XMLHttpRequest(XHR)은 AJAX 요청을 생성하는 JavaScript API입니다.
- XHR의 메서드로 브라우저와 서버간의 네트워크 요청을 전송할 수 있습니다.
// XMLHttpRequest 객체 생성 var xhr = new XMLHttpRequest(); xhr.open("GET", "<https://test.com>", true); xhr.onload = function () { if (xhr.status === 200) { var data = JSON.parse(xhr.responseText); console.log(data); } else { console.error("Request failed: " + xhr.status); } }; xhr.send();🏄♂️ 사용 방법
- XMLHttpRequest 객체 생성
- open() 메서드를 통해 요청에 필요한 정보를 설정
- send() 메서드로 서버에 요청
- 응답에 대한 콜백 함수 생성
🧩 AJAX
비동기 자바스크립트와 XML
Asynchronous Javascript and XML
웹 페이지를 전체 새로고침 없이 서버와 데이터를 비동기적으로 주고받아 부분적으로만 업데이트하는 웹 개발 기법입니다.
- 빠르게 동작하는 동적인 웹 페이지를 만들 수 있습니다.
다양한 형태의 데이터를 주고 받을 수 있습니다.
- JSON
- XML
- HTML
- 텍스트 파일 등
👋 장점
- 웹 페이지 전체를 다시 로딩하지 않고도 웹 페이지의 일부분만을 갱신해 속도가 향상되고 코딩의 양이 줄어듭니다.
- 서버의 처리가 완료될 때까지 기다리지 않고 처리가 가능하다.
- 다양한 UI를 가능하게 합니다.
⚠️ 단점
- 히스토리 관리가 되지 않습니다.
- AJAX를 쓸 수 없는 브라우저에 대한 문제 이슈 존재
- HTTP 클라이언트의 기능이 한정
- XMLHttpRequest를 통해 통신하는 경우 사용자에게 아무런 진행 정보가 주어지지 않습니다.(요청이 완료되지 않았는데 사용자가 페이지를 떠나거나 오작동 가능.)
📌 fetch
Fetch API는 네트워크 통신을 포함한 리소스 취득을 위한 인터페이스를 제공
- XMLHttpRequest보다 강력하고 유연하다.
fetch는 거의 모든 웹 브라우저가 지원하고 있습니다.
fetch를 이용하면 비동기 HTTP 요청을 만드는데 충분합니다.
🆚 fetch 와 XMLHttpRequest 차이 정리
1️⃣ 응답 처리
XHR은 콜백 을 받아 responseText, responseXMl 등을 통해 응답을 처리
fetch는 promise 를 기반으로 동작하여 response.json(), response.text()를 사용합니다.
- 프로미스를 반환하기 때문에
.then()과.catch()를 이용한 체이닝이 가능합니다.async/await문법을 사용해 코드를 더 간결하게 작성할 수 있습니다.
2️⃣ cors
XHR은 CORS를 위한 추가 설정이 필요하지만 fetch는 CORS를 지원하여 간단하게 설정이 가능합니다
fetch('url', { mode: 'cors', credentials: 'same-origin', headers: { 'Content-Type': 'application/json', }, });3️⃣ 파일 업로드 및 다운로드
XHR 에서는
progress 이벤트를 통해 업로드 진행률 데이터를 받을 수 있습니다.XHR
upload.onprogress이벤트를 사용해 업로드 진행률 추적 가능- 다운로드도
onprogress이벤트를 통해 스트리밍 중간 상태 확인 가능
fetch
- 업로드 진행률을 직접 추적하는 기능이 없음 ❌
- fetch는 스트림(Stream) 기반으로 설계되었기 때문에 전체 진행률을 한 번에 알기 어렵습니다.
- ReadableStream API를 사용하여 fetch로도 다운로드 진행률을 추적할 수는 있습니다.
4️⃣ 요청 취소
XHR
xhr.abort()메서드로 요청 취소 가능
fetch
- 기본적으로 취소 기능이 없었음
- 현재는 AbortController API로 요청 취소 가능 ✅
const controller = new AbortController(); const signal = controller.signal; fetch("<https://example.com/test>", { signal }) .then(res => res.json()) .then(data => console.log(data)) .catch(err => console.error("❌", err)); // 1초 후 요청 취소 setTimeout(() => controller.abort(), 1000);📖 사용 방법
📌 fetch
fetch 함수를 호출하는 즉시 브라우저는 HTTP 요청을 생성합니다.
fetch(url) fetch(url, options) .then(res => res.text()) .then(text => ...));- URL만 전달하여 함수를 실행할 수 있습니다 (GET 메소드로 요청)
- fetch는 기본으로 GET METHOD를 사용합니다.
📖 두 번째 인자 - options
- 헤더, 본문 등 구체적인 요청 정보를 지정해줍니다.
options 설명 method 요청 메소드 headers 요청 헤더 body 요청 본문 mode cors 관련 🏄♂️ 동작 과정
- 요청한 url로 설정한 HTTP Method로 요청을 보냅니다.
- fetch를 통해 ajax를 호출 시 해당 주소에 요청을 보낸 후 응답 객체를 받습니다.
- 첫 번째 then 에서 그 응답을 받아 res.text() 메서드로 파싱한 text 값을 리턴합니다.
- 다음 then 에서 리턴받은 text를 받고 원하는 처리를 합니다.
↗️ Json 업로드
fetch('/upload', { method: 'POST', headers: { 'Content-Type': 'application/json' } body: JSON.stringify({name: 'beomsic'}) })- body 필드에 JSON 문자열을 지정해서 요청 본문을 설정합니다.
↩️ Response
fetch 함수의 HTTP 요청은 서버로 전달되어 서버는 HTTP 응답을 다시 되돌려줍니다.
⚠️ 이 응답 데이터는 fetch 함수를 실행하면 바로 얻는 것이 아닙니다.
- 브라우저는 응답 시 실행할 콜백 함수만 등록을 한 후 다음 코드를 실행합니다.
- fetch 함수는 응답을 바로 반환하는 것이 아니라 Promise 객체를 반환합니다.
🤖 fetch 함수는 응답 대신 프라미스 객체를 반환하고 프라미스가 이행되면 Response 객체를 얻습니다. 이 Response 객체에는 HTTP 응답 정보가 담겨있습니다.
📌 주요 필드
필드 설명 status HTTP 상태 코드 (ex: 200) ok HTTP 상태코드가 200~299 사이인지 여부 body 응답 내용 headers 응답 헤더 📌 응답 본문
response.text() 응답을 읽고 텍스트를 반환 response.json() 응답을 JSON 형태로 파싱 response.formData() 응답을 FormData 객체 형태로 반환 response.blob() 응답을 Blob(타입이 있는 이진 데이터, ex: 이미지)형태로 반환 response.arrayBuffer() 응답을 ArrayBuffer(바이너리 데이터를 로우 레벨 형식으로 표현)형태로 반환 ⚠️ 주의
응답 자료 형태 반환하는 메서드는 한번만 사용가능합니다.
- response.text() 를 사용해 응답을 얻고 나면 본문의 콘텐츠는 모두 처리가 되어 response.json()을 입력해도 동작하지 않게 됩니다.
🤔 fetch 함수는 왜 프라미스를 두 번 사용할까?
async () => { try{ const response = await fetch('/test') const data = response.json(); }catch(e) { console.error(`⚠️ ERROR: ${e}`); } }1️⃣ fetch 함수가 반환하는 프로미스
2️⃣ response 객체의 메소드가 반환하는 프라미스
브라우저는 헤더를 모두 받으면 response 객체를 제공해줍니다.
- fetch 가 반환한 첫 번째 프로미스가 이행될 때
브라우저가 body 데이터를 모두 받으면 데이터를 만듭니다.
.json(),.text(),.blob()같은 본문 조회 메소드가 반환한 두 번째 프로미스가 이행될 때
✅ 시간을 지연하면서 본문을 청크 단위로 응답하는 서버
const http = require('http'); const server = http.createServer(async (req, res) => { if (req.url === '/test') { // 응답 헤더 전송 res.writeHead(200, { 'Content-Type': 'text/plain' }); // 청크 단위로 1초 간격 응답 for (const i of Array.from({ length: 5 }).keys()) { res.write(`chunk ${i}\\n`); await new Promise((resolve) => setTimeout(resolve, 1000)); } // 응답 종료 res.end(); } else { res.writeHead(404); res.end('Not Found'); } }); server.listen(3000, () => { console.log('🚀 Server running at <http://localhost:3000>'); });🖥️ curl 요청을 통해서 확인해보기

- 매초 마다
chunk x가 출력됩니다.
🌐 브라우저에서 fetch 함수는 어떻게 동작??
const response = await fetch("<http://localhost:3000/test>"); // 브라우저가 모든 헤더를 받았을 때 console.log("response:", response); // 브라우저가 body 전체 수신 및 문자열로 변환할 때 const text = await response.text(); console.log("text:", text);
- 서버가 헤더를 실어서 먼저 응답하기 때문에 Response 객체를 먼저 만들고
- 일정 시간이 지연된 뒤 모든 바디가 수신되면 text 로그가 출력됩니다.
🚀 그래서 두 번의 프로미스가 필요한 이유
1️⃣ 첫 번째 프로미스 (
fetch)- 네트워크 연결 + 응답 헤더를 받았는지 여부 확인
- "응답이 왔다!"를 알려줌 (본문은 아직일 수도 있음)
2️⃣ 두 번째 프로미스 (
.json()같은 메서드)- 응답 body를 끝까지 다 받고 응답을 받기 위해 지정한 방식(JSON, 텍스트, Blob 등)으로 파싱 완료되었을 때 알려줌
'Node.js' 카테고리의 다른 글
Logging Library (0) 2025.09.16 워커 스레드를 통한 멀티 쓰레딩 (1) 2025.08.30 비동기 프로그래밍 - Promise 와 async / await (1) 2025.08.27 Node.js - 싱글 스레드, 이벤트 루프 그리고 libuv (3) 2025.08.23 Express 을 이용해 웹페이지를 표현하는 방법 - 템플릿 엔진 (3) 2025.08.20