자바스크립트 딥다이브 - AJAX

ChoiYongHyeun·2024년 1월 2일
0
post-thumbnail

AJAX

Ajax (Asynchronous Javascript and XML) 은 자바스크립트를 사용하여 브라우저가 서버에게 비동기 방식으로 데이터를 요청하고, 서버가 응답한 데이터를 수신하여 동적으로 갱신하는 프로그래밍 방식 을 말한다.


위 네이버 페이지의 이미지를 보면, 뉴스 창에서 뉴스의 목록만 변경 할 떄 변경되는 내용에 대해서만 서버 측에 요청을 보내는 모습을 볼 수 있다. 이는 Ajax 를 이용한 것이다.

HTML 파일이 페이지에 렌더링 되는 것은 클라이언트 가 서버측에 GET 요청을 보내 HTML 파일을 받아 렌더링 한다.

이 때 HTML 파일의 일부분만 변경 할 때 Ajax 가 나타나기 전에는 일부분이 변경되더라도 , 일부분이 변경된 전체 HTML 파일을 모두 받아 렌더링했었다.

이는 새로운 렌더링이 필요하지 않은 영역까지 요청하여 렌더링 했기 때문에

서버측에서는 불필요한 데이터 통신이 발생하고

사용자는 일부분만 변경해도 새로운 HTML 을 모두 렌더링 하는 동안 기다려야 하며, 렌더링으로 인해 화면이 깜박이는 현상이 발생한다. 또한 렌더링 되는 동안 다른 행위는 하지 못하는 블로킹이 발생한다.

Ajax 는 2005년 구글 맵스에서 사용된 이후 폭발적으로 관심이 증가하였다.

하지만 Ajax를 이용하면 변경이 필요한 부분에 대해서만 변경된 HTML부분만 렌더링 하기 때문에

불필요한 데이터 통신이 일어나지도 않고 , 화면이 전체적으로 렌더링 되느라 깜박이는 현상이 발생하지 않는다.

또한Ajax 이름에서 나타나듯 비동기 적으로 처리되기 때문에 블로킹 현상도 발생하지 않는다.


JSON (Javascript Object Notation)

Ajax 를 이용하여 비동기적으로 렌더링 할 부분들에 대해서 미리 html 파일들을 만들어두는 방법도 존재하기도 하지만 JSON 이라는 자료구조를 이용하여 동적으로 렌더링 하는 방법을 자주 사용한다.

정의

JSON(제이슨[1], JavaScript Object Notation)은 속성-값 쌍(attribute–value pairs), 배열 자료형(array data types) 또는 기타 모든 시리얼화 가능한 값(serializable value) 또는 키-값 쌍으로 이루어진 데이터 오브젝트를 전달하기 위해 인간이 읽을 수 있는 텍스트를 사용하는 개방형 표준 포맷이다. 비동기 브라우저/서버 통신 (AJAX)을 위해, 넓게는 XML(AJAX가 사용)을 대체하는 주요 데이터 포맷이다. 특히 인터넷에서 자료를 주고 받을 때 그 자료를 표현하는 방법으로 알려져 있다. 자료의 종류에 큰 제한은 없으며, 특히 컴퓨터 프로그램의 변수값을 표현하는 데 적합하다.
출처 : 위키백과 - JSON

예시를 통해 JSON 의 생김새에 대해서 알아보자

{
  "squadName" : "Super Hero Squad",
  "homeTown" : "Metro City",
  "formed" : 2016,
  "secretBase" : "Super tower",
  "active" : true,
  "members" : [
    {
      "name" : "Molecule Man",
      "age" : 29,
      "secretIdentity" : "Dan Jukes",
      "powers" : [
        "Radiation resistance",
        "Turning tiny",
        "Radiation blast"
      ]
    },
    {
      "name" : "Madame Uppercut",
      "age" : 39,
      "secretIdentity" : "Jane Wilson",
      "powers" : [
        "Million tonne punch",
        "Damage resistance",
        "Superhuman reflexes"
      ]
    },
    {
      "name" : "Eternal Flame",
      "age" : 1000000,
      "secretIdentity" : "Unknown",
      "powers" : [
        "Immortality",
        "Heat Immunity",
        "Inferno",
        "Teleportation",
        "Interdimensional travel"
      ]
    }
  ]
}

MDN 홈페이지에서 제공하는 JSON 파일이다. (JSON 링크)

생김새를 보면 마치 객체 처럼 데이터를 저장하고 있는 모습을 볼 수 있다.

JSON 은 데이터를 효과적으로 표현하고 전송하기 위한 간단하면서도 가벼운 데이터 교환 형식을 지원한다.

JSON은 사람이 읽고 쓰기 쉬운 형식을 가지고 있으며 (객체처럼 생겼다)

자바스크립트에서는 텍스트 형식인 JSON 파일을 자바스크립트 객체 로 변환 할 수 있기 때문에 개발자 입장에서는 JSON 데이터를 쉽게 다룰 수 있다.

Ajax 이름에 XML이 들어가는데 왜 JSON 을 설명하나요

AjaxXML 뿐이 아니라 비동기적으로 데이터를 교환하는 방식을 의미한다.
JSONXML에 비해 가독성이 좋고 간결하며 더 적은 크기를 가지고 있기 때문에 더 자주 사용된다.
그러니 그냥 JSON 공부해 ~!!!

XMLHttpRequest

JSON 이 담긴 URL 에게 JSON 파일을 받기 위한 request 를 요청하려면 Web APIXMLHttpRequest 객체를 이용한다.

const request = new XMLHttpRequest();

생성자 함수로 XMLHttpRequest객체를 생성하고, 생성된 객체의 프로퍼티와 메소드를 이용해 HTTP request 를 보낼 수 있다.

XMLHttpRequest 프로퍼티

프로퍼티 설명
onreadystatechange 상태 변경 이벤트를 처리하는 이벤트 핸들러입니다.
readyState 요청의 현재 상태를 나타내는 값으로, 0부터 4까지의 값을 가집니다.
response 요청에 대한 응답 데이터를 나타냅니다. (읽기 전용)
responseText 응답 데이터를 문자열로 반환합니다.
responseType 응답 데이터의 형식을 나타내는 문자열로, "text", "json", "document" 등이 있습니다.
status HTTP 상태 코드를 나타냅니다.
statusText HTTP 상태 코드에 대한 설명을 나타냅니다.
timeout 요청이 지연되기 전에 대기할 시간(밀리초)을 나타냅니다.
withCredentials 크로스 오리진 요청일 때 인증 정보를 포함할지 여부를 나타냅니다.

대표적인 프로퍼티들은 다음과 같다.

프로퍼티를 이용하여 request 를 보낼 XMLHttpRequest 객체의 요청 타입이나 요청 상태 등을 확인 할 수 있다.

XMLHttpRequest 의 프로토타입 메소드

메서드 설명
open(method, url, async) 요청의 초기 설정을 수행합니다. HTTP 메서드, URL, 비동기 여부 등을 설정합니다.
send(data) 요청을 서버로 보냅니다. 데이터를 인자로 전달할 수 있습니다.
setRequestHeader(header, value) HTTP 헤더를 설정합니다. 요청 전에 호출되어야 합니다.
abort() 현재의 HTTP 요청을 취소합니다.
getAllResponseHeaders() 응답에 포함된 모든 헤더를 반환합니다.
getResponseHeader(header) 특정 헤더의 값을 반환합니다.

프로토타입 메소드를 통해 URL 주소로 요청을 보내기 위한 준비, 보내기, 취소 등을 할 수 있다.

XMLHttpRequest 의 이벤트 핸들러 프로퍼티

프로퍼티 설명
onreadystatechange readyState 속성이 변경될 때 호출되는 이벤트 핸들러를 설정하거나 반환합니다.
onload 요청이 성공적으로 완료될 때 호출되는 이벤트 핸들러입니다.
onerror 요청이 실패할 때 호출되는 이벤트 핸들러입니다.
ontimeout 타임아웃이 발생했을 때 호출되는 이벤트 핸들러입니다.
onprogress 요청이 진행 중일 때 주기적으로 호출되는 이벤트 핸들러입니다.

이벤트 핸들러 프로퍼티는 다음과 같다.

사실 위의 3개를 달달달 외우기보다 실습하면서 복습해보자

XMLHttpRequest 실습하기

사용하고자 하는 JSON 파일의 형태는 다음과 같다.

{
  "squadName" : "Super Hero Squad",
  "homeTown" : "Metro City",
  "formed" : 2016,
  "secretBase" : "Super tower",
  "active" : true,
  "members" : [
    {
      "name" : "Molecule Man",
      "age" : 29,
      "secretIdentity" : "Dan Jukes",
      "powers" : [
        "Radiation resistance",
        "Turning tiny",
        "Radiation blast"
      ]
    },
    ...

Suepr Hero Squad 와 관련된 정보들이 담겨있으며 members 라는 키에는 배열로 된 값이 존재한다.

JSON 파일의 URLMDN 에서 제공하는 URL 을 이용하기로 하자

HTML

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <button>request</button>
    <header></header>
    <section></section>
  </body>
  <script src="request.js"></script>
</html>

맨 처음 초기페이지의 경우에는 버튼만 딸랑 존재하며 해당 버튼을 누르면 JSON 파일이 담긴 URLrequest 를 보내 JSON 파일을 파싱해오고, 파싱한 파일을 가지고 동적으로 렌더링해보자

Script

변수 설정

const $button = document.querySelector('button');
const request = new XMLHttpRequest();
const URL =
  'https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json';

버튼에 이벤트 핸들러를 장착하기 위해 버튼 태그를 설정하고

XMLRequestHttp 객체를 생성하자

sendRequest

const sendRequest = () => {
  // HTTP 요청 초기화
  request.open('GET', URL);
  // HTTP 수신 설정
  request.responseType = 'json';
  // HTTP 요청 보내기
  request.send();
};

버튼이 눌리면 요청을 보낼 콜백 함수를 생성했다.

.open(method , url) 프로토타입 메소드를 통해 요청을 보낼 URL 주소와 보낼 요청을 설정해준다.

이후 requestresponseType 프로퍼티를 json 으로 설정해, 파싱해올 데이터가 JSON 형식임을 알려줘 파싱해올 때 자바스크립트의 객체 형식으로 변화 시킬 수 있도록 한다.

// 버튼이 눌리면 JSON 파일이 있는 URL에 GET 요청을 보내 JSON 파일을 가져옴

$button.addEventListener('click', () => {
  if (request.readyState !== 0) return;
  sendRequest();
});

버튼이 눌리면 해당 콜백 함수를 시행하고, 파싱해온 JSON 파일을 살펴보자

// 요청이 완료되면 파싱해온 객체를 로그하자

request.addEventListener('load', () => {
  console.log(request.response);
});

요청이 완료되면 요청해온 값이 response 프로퍼티에 담기기 때문에

load 가 되면 로그하도록 이벤트 핸들러를 등록해주었다.

버튼이 눌리면 개발자 도구 - network 창에서 볼 수 있듯이 해당 json 파일을 가져오고

파싱해온 json 파일은 객체 형식으로 존재하는 모습을 볼 수 있다.

그럼 이제 객체 형식으로 파싱된 json 파일을 가지고 DOM 을 조작하여 페이지를 꾸밀 수 있다.

popularHeader , shwHeroes

// 기존 html 에 존재하는 header 태그 가져오기
const $header = document.querySelector('header');

// JSON의 프로퍼티로 접근하여 header에 내용 붙이기
const populateHeader = (jsonObj) => {
  const $h1 = document.createElement('h1');
  $h1.textContent = jsonObj.squadName;
  $header.appendChild($h1);

  const $p = document.createElement('p');
  $p.textContent = `Hometown : ${jsonObj.homeTown} // Formed : ${jsonObj.formed} `;

  $header.appendChild($p);
};

// JSON의 프로퍼티에 접근하여 article에 내용 붙이기

const showHeroes = (jsonObj) => {
  const heroes = jsonObj.members; // json 내의 members의 프로퍼티 값은 유사배열 객체
  const $section = document.querySelector('section');
  [...heroes].forEach((hero) => {
    const $div = document.createElement('div');
    const $h2 = document.createElement('h2');
    const $p1 = document.createElement('p');
    const $p2 = document.createElement('p');
    const $p3 = document.createElement('p');
    const $ul = document.createElement('ul');

    $h2.textContent = hero.name;
    $p1.textContent = `Secret identity : ${hero.secretidentity}`;
    $p2.textContent = `Age : ${hero.age}`;
    $p3.textContent = 'SuperPowers:';

    const superPowers = hero.powers; // hero.power 는 배열

    superPowers.forEach((power) => {
      const $li = document.createElement('li');
      $li.textContent = power;
      $ul.appendChild($li);
    });

    [$h2, $p1, $p2, $p3, $ul].forEach((tag) => $div.appendChild(tag));
    $section.appendChild($div);
  });
};

// 요청이 완료되면 요청한 불러온 JSON 파일을 이용하여 태그 생성하기
request.addEventListener('load', () => {
  const superHeroes = request.response;
  populateHeader(superHeroes);
  showHeroes(superHeroes);
});

파싱해온 JSON을 이용하여 동적으로 DOM 을 생성하고 페이지에 렌더링 해주었다.

DOM 을 조작하는 것이 해당 챕터의 주제는 아니기 때문에 자세히 쓰지는 않겠다.

다만 파싱된 JSON자바스크립트의 객체 형식으로 오기 때문에 파싱해온 JSON 의 키와 값을 이용해

렌더링을 해줄 수 있었다.

위에서 Ajax 의 장점에 대해서 비동기 통신과 서버 부하 감소, UX 향상 등에 대해서도 말하였지만

그 뿐만 아니라

실시간으로 변하는 데이터를 렌더링 해야 하는 경우 (예를 들어 게시글, 댓글 등) 변한 데이터를 JSON에 저장하고 변한 데이터만을 렌더링 하면 되기 때문에 실시간 업데이트가 가능하다.

JSON 다루기

JSON 은 자바스크립트의 객체 형식과 매우 유사하며, 자바스크립트는 문자열 형식인 JSON 을 자바스크립트의 객체 형식으로 파싱해와 다루기 쉽게 만든다.

그럼 어떻게 할까 ?

JSON.stringify

JSON.stringify 는 객체를 JSON 포맷의 문자열로 변환한다.

이는 클라이언트가 서버로 객체를 전송하려면 객체를 문자열화 하여야 하는데 이를 직렬화 라고 한다.

const obj = {
  name: 'lee',
  age: 20,
  alive: true,
  hobby: ['soccer', 'bascketball'],
};

다음과 같은 객체가 있을 때

const json = JSON.stringify(obj);
console.log(json); 
// {"name":"lee","age":20,"alive":true,"hobby":["soccer","bascketball"]}

다음과 같이 객체를 JSON 표기 방식에 맞게 직렬화 해준다.

매개변수를 보면 valuereplacer , space 가 존재한다.

value 는 직렬화 할 객체를 넣어주면 된다.

replacer

replacer 에는 콜백함수배열 이 들어 갈 수 있다.

콜백함수

JSON.stringify 가 실행 될 때 콜백함수에는 key , value 값이 매개변수로 들어간다.

const replacer = (key, value) => {
  if (key === 'name') return undefined;

  if (typeof value === 'boolean') return undefined;
  return value;
};

const json = JSON.stringify(obj, replacer);
console.log(json); // {"age":20,"hobby":["soccer","bascketball"]}

stringify 는 반환값이 undefined 가 아닌 값들에 대해서만 직렬화 하기 때문에 조건에 맞지 않는 값들은 JSON 형태로 저장되지 않은 모습을 볼 수 있다.

배열


const json = JSON.stringify(obj, ['age', 'alive']);
console.log(json); // {"age":20,"alive":true}

배열 형태에선 배열에만 존재하는 key 값을 직렬화 한다.

space

space 인수는 json 문자열의 들여쓰기 정도를 나타낸다.

const json = JSON.stringify(obj, null, 2);
console.log(json);
/**
{
    "name": "lee",
    "age": 20,
    "alive": true,
    "hobby": [
        "soccer",
        "bascketball"
    ]
}
*/

JSON.parse

JSON.parse 는 반대로 문자열 형태의 JSON자바스크립트 객체 타입으로 파싱한다.

const obj = {
  name: 'lee',
  age: 20,
  alive: true,
  hobby: ['soccer', 'bascketball'],
};

const json = JSON.stringify(obj, null, 4);

console.log(JSON.parse(json));

/**
{
  name: 'lee',
  age: 20,
  alive: true,
  hobby: [ 'soccer', 'bascketball' ]
}
*/

인수를 보면 reviver 이라는 값이 존재한다.

reviver

reviver 은 문자열을 파싱 할 때 속성에 대해 호출되며, 키와 값을 가지고 조건에 따라 객체로 변환 될 떼 값을 변경 할 수 있다.

const json = JSON.stringify(obj, null, 4);
const result = JSON.parse(json, (key, value) => {
  if (value === true) return '살았지롱';
  return value;
});
console.log(result);

/*
{
  name: 'lee',
  age: 20,
  alive: '살았지롱',
  hobby: [ 'soccer', 'bascketball' ]
}
*/
profile
빨리 가는 유일한 방법은 제대로 가는 것이다

0개의 댓글