Ajax 실시간 갱신 - Ajax silsigan gaengsin

Ajax 실시간 갱신 - Ajax silsigan gaengsin

안녕하세요. 이번 포스팅에서는 AJAX에 대해 알아보겠습니다.

AJAX(Asynchronous Javascript And Xml)는 클라이언트와 서버간의 데이터를 비동기 방식으로 주고 받는 기술을 의미합니다.

AJAX는 데이터를 딱 필요한 부분만 별도로 요청하여 응답을 받아 처리하기 때문에 사용자가 대기하는 시간을 줄일 수 있다는 장점이 있습니다.

이것이 가능한 이유는 기존의 데이터를 처리하는 방식인 동기 방식이 아니라, 비동기 방식으로 데이터를 요청/처리하기 때문입니다.

* 동기(Synchronous) 방식이란 클라이언트에서 요청(request)을 보내면 서버에서 응답(response)가 돌아오기 전까지 무작정 기다려야만 하는 방식입니다. 
웹 페이지의 일부분만 바꾸려고 요청을 해도 서버에서 해당 페이지의 전체 데이터를 응답받기 때문에 페이지가 새로고침됩니다.
* 비동기(Asynchronous) 방식은 클라이언트에서 요청(request)를 보내면 서버에서 응답(response)가 돌아오기 전까지 기다리지 않고 다른 행위를 할 수 있습니다.
뿐만 아니라 웹 페이지의 일부분의 데이터만 요청을 하면 요청된 부분만 서버로부터 받아오기 때문에 페이지가 새로고침될 필요가 없습니다.

AJAX에는 XML이란 단어가 들어가 XML로 구성된 데이터만 통신이 가능한 것으로 헷갈리실 수도 있습니다. 

하지만 AJAX는 XML뿐만 아니라 HTML, TEXT, JSON 형식의 데이터도 처리가 가능합니다.


예시를 통해 AJAX를 이해해보도록 하겠습니다.

Ajax 실시간 갱신 - Ajax silsigan gaengsin
게시글을 읽어오기 전 초기 페이지

input에 숫자를 입력하고 게시글 읽어오기를 클릭하면 서버에서 해당 숫자에 일치하는 데이터를 AJAX 방식을 통해 불러오도록 하겠습니다.

위의 HTML, CSS는 다음과 같습니다.

<!-- HTML -->

<input type="text" id="user-id">
<button type="button" onclick="loadArticles()">게시글 읽어오기</button>

<table id="list" width="100%">
    <thead>
        <tr>
            <th>타이틀</th>
            <th>댓글 수</th>
        </tr>
    </thead>
    <tbody>
    </tbody>
</table>
/* CSS */

<style>
  table {
      border-spacing: 0;
  }

  table tr th {
      border-bottom: 2px solid black;
      padding: 5px;
  }

  table tr td {
      border-bottom: 1px solid black;
      padding: 5px;
  }
 </style>

위의 HTML 코드를 보시면 '게시글 읽어오기' 버튼을 클릭할 때 onclick 이벤트가 실행되어 loadArticles 함수가 호출됩니다.

loadArticles 함수를 구현해보도록 하겠습니다.

function loadArticles() {
    const userId = document.querySelector('#user-id').value; // input의 value를 뽑아낸다.
    const xhr = new XMLHttpRequest(); // XMLHttpRequest 인스턴스의 open(), send() 메서드를 사용하기 위해 인스턴스를 생성한다.

    xhr.onreadystatechange = function() {
        if (this.readyState === 4) {
            const response = JSON.parse(this.responseText);
            
            for (let i = 0; i < response.length; i++)
                loadComments(response[i]);
        }
    }
    
    xhr.open('get', 'https://jsonplaceholder.typicode.com/posts?userId=' + userId, true);
    xhr.send();
}

XMLHttpRequest는 비동기 통신을 위해서 브라우저에서 제공하는 객체입니다.  

AJAX 처리를 위해서는 해당 객체를 통해 인스턴스를 생성하여 open(), send() 메서드를 사용해야 합니다.

open, send 메서드를 설명하기에 앞서 onreadstatechange 이벤트부터 설명하겠습니다

onreadystatechange 이벤트는 readyState 속성값이 변할 때마다 자동으로 호출될 함수나 함수명을 저장합니다. 

현재 예시로는 호출될 함수를 저장(콜백함수)하고 있습니다. 

if문의 부분을 따로 함수를 만들어서 끼워넣는 것도 가능합니다.

readyState는 XMLHttpRequest 객체의 현재 상태를 갖고 있으며 0 ~ 4의 값을 가집니다.

0 요청이 초기화되지 않았습니다.
1 서버와 연결되었습니다.
2 요청이 받아들여졌습니다.
3 요청이 진행중입니다.
4 요청이 완료되고 응답을 받았습니다.

readyState는 0부터 4까지 차례대로 값이 바뀌기 때문에 중간에 콘솔을 찍어 출력해보면 총 5번이 찍히는 것을 확인할 수 있습니다.(데이터를 정상적으로 가져왔다는 가정하에)

open() 메서드는 서버로 보낼 AJAX 요청의 형식을 설정합니다.

서버에게 '난 이렇게 데이터를 요청하겠다'라는 의미입니다.

open(전달 방식, URL 주소, 비동기여부);

전달 방식에서는 GET, POST 방식 중 하나를 선택할 수 있습니다.

URL 주소는 클라이언트의 요청을 처리할 서버측의 주소입니다.

세 번째 인자는 true이면 비동기, false이면 동기를 뜻합니다.

send() 메서드는 작성된 AJAX 요청을 서버로 전달하는 역할을 합니다.

이 메서드는 전달 방식에 따라 매개변수가 있을 수도 없을 수도 있습니다.

send(); // GET 방식
send(문자열); // POST 방식

단, POST 방식인 경우에는 open()과 send() 사이에 setRequestHeader 메서드를 통해 헤더를 설정해야 합니다.

xhr.onreadystatechange = function() {
    if (this.readyState === 4) {
        const response = JSON.parse(this.responseText);
            
        for (let i = 0; i < response.length; i++)
            loadComments(response[i]);
    }
}

이 부분을 살펴보도록 하겠습니다.

우선 send()를 통해 요청을 보냈고 응답을 잘 받아서 this.readyState === 4 가 true라고 가정을 하겠습니다.

console.log(this.responseText);를 통해 어떠한 데이터를 받아왔는지 콘솔에 출력하면 다음과 같습니다.

Ajax 실시간 갱신 - Ajax silsigan gaengsin

서버측으로부터 받은 데이터는 String 객체로 받아왔습니다.

자바스크립트에서는 String 객체로 받아온 데이터를 그대로 사용을 할 수가 없기 때문에 JSON 객체로 변환하는 과정을 거쳐야 합니다.

이러한 방법은 JSON.parse 메서드를 사용하면 됩니다.

JSON.parse를 통해 JSON 객체로 변환시켜주고 콘솔을 찍어보면 다음과 같습니다.

Ajax 실시간 갱신 - Ajax silsigan gaengsin
이제 이 데이터를 직접 활용할 수 있습니다.

이후 response.length 만큼 for문을 순회하면서 loadComments 함수를 호출합니다.

loadComments 함수는 다음과 같습니다.

function loadComments(article) {
    const xhr = new XMLHttpRequest();

    xhr.onreadystatechange = function() {
        if (this.readyState === 4) {
            const response = JSON.parse(this.responseText);
            
            const html = `
                <tr>
                        <td>${article.title}</td>
                        <td>${response.length}</td>    
                </tr>
            `;
                        
                        
            const table = document.querySelector('#list');
            table.insertAdjacentHTML('beforeend', html);
        }
    }

    xhr.open('get', 'https://jsonplaceholder.typicode.com/comments?postId=' + article.id, true);
    xhr.send();
 }

loadComments 함수도 loadArticles 함수가 동작하는 원리는 동일합니다.

loadComments 함수에서는 인자로 받은 article을 통해 동적으로 노드를 조작해야 합니다.

왜냐하면 불러오는 데이터의 개수를 예상할 수 없으니 받아오는대로 동적으로 데이터를 HTML에 추가해주기 위함입니다.

es6 템플릿을 활용하여 노드를 조작해보았습니다.

이렇게 AJAX 통신을 하여 불러온 데이터를 화면에 뿌린 결과는 다음과 같습니다.

Ajax 실시간 갱신 - Ajax silsigan gaengsin
결과