43장 AJAX
43.1 AJAX란?
핵심 포인트:
- 브라우저가 서버와 백그라운드 통신을 수행한다.
- 전체 새로고침 없이 UI 일부만 업데이트한다.
- 초기 AJAX는 XML을 자주 썼지만, 현재는 JSON이 사실상 표준이다.
전통적인 동기 요청 방식과의 차이
전통적인 방식은 요청할 때마다 페이지 전환 또는 전체 리로드가 발생하기 쉽다. 반면 AJAX는 필요한 시점에 필요한 데이터만 받아와 사용자 경험을 개선한다.
**AJAX(Asynchronous JavaScript and XML)**는 자바스크립트를 사용해 브라우저가 서버와 비동기 방식으로 데이터를 주고받는 기법이다.
페이지 전체를 다시 로드하지 않고도 필요한 데이터만 받아 화면 일부를 갱신할 수 있다.

- 이전 웹페이지와 차이가 없어서 변경할 필요가 없는 부분까지 포함한 완전한 HTML을 서버로부터 매번 다시 전송 받기 때문에 불필요한 데이터 통신이 발생한다.
- 클라이언트와 서버와의 통신이 동기 방식으로 작동하기 때문에 서버로부터 응답이 있을 때까지 다음 처리는 블로킹 된다.

AJAX의 장점:
- 빠른 반응성(체감 성능 향상)
- 네트워크 트래픽 절감(필요 데이터만 교환)
- 더 자연스러운 사용자 인터랙션
43.2 JSON
43.2.1 JSON 표기 방식
JSON(JavaScript Object Notation)은 키-값 구조의 텍스트 데이터 포맷이다. 사람이 읽기 쉽고, 다양한 언어에서 쉽게 파싱할 수 있다.
규칙 요약:
- 키는 큰따옴표(
")로 묶는다. - 문자열 값도 큰따옴표를 사용한다.
- 숫자, 불리언, null, 객체, 배열을 값으로 가질 수 있다.
{
"id": 1,
"name": "Evan",
"active": true,
"tags": ["js", "ajax"]
}43.2.2 직렬화/역직렬화
JSON.stringify(value): 객체 -> JSON 문자열JSON.parse(text): JSON 문자열 -> 객체
const user = { id: 1, name: 'Evan' };
const json = JSON.stringify(user); // "{\"id\":1,\"name\":\"Evan\"}"
const parsed = JSON.parse(json); // { id: 1, name: 'Evan' }43.3 XMLHttpRequest
XMLHttpRequest(XHR)는 브라우저에서 HTTP 요청을 보내고 응답을 받기 위한 객체다.
AJAX 구현의 전통적인 핵심 API이며, 현재는 fetch를 더 많이 쓰지만 XHR 이해는 중요하다.
43.3.1 기본 사용 순서
XMLHttpRequest객체 생성open(method, url)로 요청 초기화- 필요 시
setRequestHeader로 헤더 설정 send(body)로 전송- 이벤트 핸들러에서 상태/응답 처리
43.3.2 XHR 객체의 프로토타입와 메서드
- XMLHttpRequest 객체의 프로토타입 프로퍼티
| 프로토타입 프로퍼티 | 설명 |
|---|---|
| readyState | HTTP 요청의 현재 상태를 나타내는 정수. 다음과 같은 XMLHttpRequest의 정적 프로퍼티를 값으로 갖는다. - UNSENT: 0 - OPENED: 1 - HEADERS_RECEIVED: 2 - LOADING: 3 - DONE: 4 |
| status | HTTP 요청에 대한 응답 상태(HTTP 상태 코드)를 나타내는 정수 (예: 200) |
| statusText | HTTP 요청에 대한 응답 메시지를 나타내는 문자열 (예: “OK”) |
| responseType | HTTP 응답 타입 (예: document, json, text, blob, arraybuffer) |
| response | HTTP 요청에 대한 응답 몸체(response body). responseType에 따라 타입이 다르다. |
| responseText | 서버가 전송한 HTTP 요청에 대한 응답 문자열 |
- XMLHttpRequest 객체의 이벤트 핸들러 프로퍼티
| 이벤트 핸들러 프로퍼티 | 설명 |
|---|---|
| onreadystatechange | readyState 프로퍼티 값이 변경된 경우 |
| onloadstart | HTTP 요청에 대한 응답을 받기 시작한 경우 |
| onprogress | HTTP 요청에 대한 응답을 받는 도중 주기적으로 발생 |
| onabort | abort 메서드에 의해 HTTP 요청이 중단된 경우 |
| onerror | HTTP 요청에 에러가 발생한 경우 |
| onload | HTTP 요청이 성공적으로 완료한 경우 |
| ontimeout | HTTP 요청 시간이 초과한 경우 |
| onloadend | HTTP 요청이 완료된 경우. HTTP 요청이 성공 또는 실패하면 발생 |
- XMLHttpRequest 객체의 메서드
| 메서드 | 설명 |
|---|---|
| open | HTTP 요청 초기화 |
| send | HTTP 요청 전송 |
| abort | 이미 전송된 HTTP 요청 중단 |
| setRequestHeader | 특정 HTTP 요청 헤더의 값을 설정 |
| getResponseHeader | 특정 HTTP 요청 헤더의 값을 문자열로 반환 |
- XMLHttpRequest 객체의 정적 프로퍼티
| 정적 프로퍼티 | 값 | 설명 |
|---|---|---|
| UNSENT | 0 | open 메서드 호출 이전 |
| OPENED | 1 | open 메서드 호출 이후 |
| HEADERS_RECEIVED | 2 | send 메서드 호출 이후 |
| LOADING | 3 | 서버 응답 중 (응답 데이터 미완성 상태) |
| DONE | 4 | 서버 응답 완료 |
43.3.3 HTTP 요청 전송
GET 요청 예시
const xhr = new XMLHttpRequest();
xhr.open('GET', '/users');
xhr.send();
xhr.onload = () => {
if (xhr.status === 200) {
const data = JSON.parse(xhr.response);
console.log(data);
return;
}
console.error('요청 실패:', xhr.status, xhr.statusText);
};POST 요청 예시
const xhr = new XMLHttpRequest();
xhr.open('POST', '/users');
xhr.setRequestHeader('content-type', 'application/json');
xhr.send(JSON.stringify({ name: 'Lee', age: 30 }));
xhr.onload = () => {
if (xhr.status === 200 || xhr.status === 201) {
console.log('생성 완료:', JSON.parse(xhr.response));
return;
}
console.error('생성 실패:', xhr.status, xhr.statusText);
};43.3.4 HTTP 응답 처리
status
status는 HTTP 상태 코드다.
200: 성공201: 생성 성공400대: 클라이언트 오류500대: 서버 오류
readyState
readyState는 요청 진행 상태다.
0: UNSENT1: OPENED2: HEADERS_RECEIVED3: LOADING4: DONE
실무에서는 onload, onerror를 자주 사용하고,
필요하면 onreadystatechange에서 readyState === 4를 확인해 처리한다.
에러 처리 포인트
- 네트워크 실패:
onerror - 타임아웃:
timeout+ontimeout - HTTP 실패:
status코드로 분기
const xhr = new XMLHttpRequest();
xhr.open('GET', '/users');
xhr.timeout = 5000;
xhr.onload = () => {
if (xhr.status >= 200 && xhr.status < 300) {
console.log(JSON.parse(xhr.response));
return;
}
console.error('HTTP 에러:', xhr.status);
};
xhr.onerror = () => console.error('네트워크 에러');
xhr.ontimeout = () => console.error('요청 타임아웃');
xhr.send();AJAX의 한계와 fetch
XHR은 이벤트 기반이라 코드가 길어지기 쉽고, 복잡한 흐름에서 가독성이 떨어질 수 있다.
그래서 현대 자바스크립트에서는 Promise 기반의 fetch를 더 많이 사용한다.
다만 레거시 코드나 라이브러리 내부 동작을 이해하려면 XHR 지식이 필요하다.
개념 점검 퀴즈 (5문제)
퀴즈 1
AJAX의 가장 큰 특징을 한 문장으로 설명해보세요.
퀴즈 2
JSON.stringify와 JSON.parse의 역할을 각각 쓰세요.
퀴즈 3
XHR에서 요청이 완전히 끝난 상태를 나타내는 readyState 값은 무엇인가요?
퀴즈 4
POST /users 요청에서 보통 setRequestHeader('content-type', 'application/json')을 설정하는 이유는 무엇인가요?
퀴즈 5
HTTP 상태 코드 관점에서 200과 201의 차이를 설명해보세요.