[개념 설명] AJAX

혜빈·2024년 8월 12일

보충내용

목록 보기
15/38

AJAX

-Asynchronous JavaScript And XML

  • AJAX 등장 이전에는 웹페이지에서의 모든 사용자 행동은 재접속을 통해 이루어짐
  • 만약 웹 사이트에 접속하기 위해 브라우저의 주소창에 URL을 입력하면
    브라우저가 서버에게 해당 URL로 요청을 보내고
    서버는 해당 웹페이지를 구성하는 HTML, CSS, JavaScript 파일, 이미지를 비롯한 리소스들을 보냄
  • 브라우저는 이들을 읽어들여 사용자가 보는 페이지를 보여줌
  • 사용자가 어떤 게시물의 좋아요 버튼을 누르면 브라우저는 그에 해당하는 요청을 서버로 보내고
    서버는 그것이 반영된 웹페이지의 모든 리소스를 다시 브라우저에게 보냄
  • 브라우저는 열려있던 페이지를 닫고 받아온 리소스들로 새로운 페이지를 열어야 함
  • 바뀐 요소는 좋아요 버튼 하나지만, 이를 위해 모든 것을 새로 열어야하는 비효율적인 현상이 발생함
  • 사용자의 모든 행동마다 화면이 깜빡이는 불편한 사용자 경험과, 매 번 모든 리소스가 새로 받아와지면서 발생하는 네트워크 트래픽 낭비 문제가 발생함 -> AJAX를 사용하면 해결됨

AJAX를 사용하면?

  • 사용자가 좋아요 버튼 클릭시, 브라우저는 서버에게 이를 반영하라는 HTTP 요청을 보냄
  • 서버는 이 요청을 받아 그에 해당하는 데이터베이스 관련 작업을 마친 뒤, 사용자와 해당 게시물의 좋아요 여부에 관련된 업데이트 정보를 보내줌
    (불필요한 정보와 리소스는 전송하지 않음)
  • 브라우저는 이 응답을 받고, 그 안에 담긴 정보에 기반하여 웹페이지를 동적으로 수정함
  • JavaScript로 DOM을 조작해서, 해당 버튼을 선택한 뒤 좋아요 표시를 활성화해줌
  • 사용자는 깜빡이는 새로고침 과정 없이 좋아요 버튼만 색이 바뀌는 것을 확인할 수 있음
  • 이처럼 웹페이지에 새로 접속하지 않고 필요한 정보만 지속적으로 받아와서 웹페이지를 업데이트하는 AJAX는 웹 서핑을 편리하게 해줌

사용 예시

  • 검색창에 텍스트가 입력될 때마다 자동으로 검색어 추천해주는 것
  • 지도 드래그, 줌 인, 줌 아웃 할 때마다 해당 위치와 축적에 맞는 정보들과 이미지들이 화면을 채우는 것
  • 스크롤 다운 할 때마다 계속해서 새로운 항목들이 나타나는 것
  • AJAX가 고안되었을 때는 JSON이 대중화되기 전이었기 때문에 데이터의 표현에 XML이 많이 사용됨
  • 오늘날에는 보다 간결하고 가독성이 좋은 JSON이 가장 많이 사용되고, 그 외 다양한 형식들도 AJAX에서 사용될 수 있음
  • 비동기 작업 : 여러 작업들이 동시에 진행될 수 있고, 한 작업이 지연되는 것이 다른 작업을 방해하거나 가로막지 않음
    차량이 다차선 도로에서 달리는 것과 같이 모든 작업들이 서로 독립적임
  • 동기 작업 : 차량들이 하나의 길에서 달리는 것과 같아서 느린 작업에 의한 병목현상 발생 가능
  • AJAX는 (Asynchronous) 비동기적으로 이루어지기 때문에 웹 페이지에서 진행되고 있는 다른 작업들을 방해하지 않음

AJAX 구현 방법 (XMLHTTPRequest VS Fetch API)

  • 둘 다 Web API의 일부임
  • Web API란 제대로 된 브라우저라면 마땅히 제공하기로 되어있는 기능들임
  • 따라서 따로 설치하지 않고도 사용 가능함
  • 전에는 XMLHTTPRequest 및 이를 활용해서 만든 axios 등의 라이브러리 들을 많이 사용했는데
    Fetch API 도입 이후에는 보다 간결하면서 편리한 Fetch API가 점점 더 많이 사용되고 있음

실제 구현 예시

  • 얄코님 코드 참고

  • HTML 문서에서 각 주제의 제목과 설명글이 나타나야 할 곳을 처음에 비워둠

<h2></h2>
<p></p>
  • 탭의 버튼들에도 선택된 것을 표시하기 위한 클래스가 붙어있지 않음
      <nav>
        <ul>
          <li class="javascript">JavaScript</li>
          <li class="react">React</li>
          <li class="dom">Dom</li>
          <li class="ssr">SSR</li>
        </ul>
      </nav>
  • 이것들은 JavaScript 코드에 의해 동적으로 채워지게 됨

XMLHTTPRequest 버전

  1. 함수 내부에 XMLHTTPRequest의 인스턴스 생성
  2. open 메소드를 사용해서 이 주소에 있는 json 파일의 내용을 서버로부터 받아옴
function 함수(code) {
  const xhr = new XMLHttpRequest();
  xhr.open('GET', './apis.json', true);
}
  • 해당 json 파일에는 각 주제들에 대한 데이터가 배열 형태로 들어있음
[
  {
    "code": "javaScript",
    "name": "JavaScript",
    "content": "JavaScript는 이런 특징을 가지고 있습니다."
  },
  {
    "code": "react",
    "name": "React",
    "content": "React는 이런 특징을 가지고 있습니다."
  },
  {
    "code": "dom",
    "name": "Dom",
    "content": "Dom은 이런 특징을 가지고 있습니다."
  },
  {
    "code": "ssr",
    "name": "SSR",
    "content": "SSR은 이런 특징을 가지고 있습니다."
  }
]
  • 실무에서는 선택된 특정 주제의 데이터만 서버의 데이터베이스에서 추출하여 보내주는 것이 보통임
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      // 응답이 성공적으로 돌아왔을 때 실행할 일
      if (xhr.status === 200) {
        try {
          // 서버로부터 받아온 JSON 형식의 텍스트를 파싱해서 데이터 추출
          const data = JSON.parse(xhr.responseText);
          const api = data.find(api => api.code === code);
          
          // DOM의 기능들을 사용해서 요소들을 선택
          document.querySelectorAll('#contents nav ul li')
          // select 클래스를 더하거나 빼서 선택된 탭을 표시
            .forEach(li => { li.classList.remove('selected') });

          document.querySelector(`#contents nav ul li.${code}`)
            .classList.add('selected');

          document.querySelector('#contents h2')
          	// textContent 속성을 통해 제목과 내용을 채워 넣음
            .textContent = api.name;

          document.querySelector('#contents p')
            .textContent = api.content;
        } catch (e) {
          console.error('Error parsing JSON:', e);
        }
      } else {
        console.error('Network response was not ok');
      }
    }
  };

// 문제 발생시 실행할 함수 넣어주기
  xhr.onerror = function() {
    console.error('Request error');
  };

// send 메소드로 요청을 서버에 보냄
  xhr.send();
}

document.querySelectorAll('#contents ul li')
.forEach(li => {
  li.addEventListener('click', function(e) {
    const code = Array.from(e.target.classList)
    .find(c => { return c != 'selected' })
    // 사용자가 이 탭의 버튼들 중 하나를 클릭할 때, 웹 페이지가 처음 열릴 때 각 주제의 코드와 함께 실행됨
    getContents(code);
  });
});

getContents('javascript')

Fetch API 버전

function getContents (code) {
  fetch('./apis.json')
  .then(response => {
    if (!response.ok) {
      throw new Error('Network response was not ok');
    }
    return response.json();
  })
  .then(data => {
    const api = data.find(api => api.code === code);
    document.querySelectorAll('#contents nav ul li')
    .forEach(li => {li.classList.remove('selected')})

    document.querySelector(`#contents nav ul li.${code}`)
    .classList.add('selected');

    document.querySelector('#contents h2')
    .textContent = api.name;

    document.querySelector('#contents p')
    .textContent = api.content;
  })
  .catch(error => {
    console.error('Error ocurred:', error);
  });
}

document.querySelectorAll('#contents ul li')
.forEach(li => {
  li.addEventListener('click', function(e) {
    const code = Array.from(e.target.classList)
    .find(c => { return c != 'selected' })
    getContents(code);
  });
});

getContents('javascript');
  • JavaScript의 promise를 사용하여 작성함
  • method chaining을 사용해서 보다 간결하고 직관적인 함수형 코드를 짤 수 있음
  • then 메소드에는 받아온 데이터를 사용해서 실행할 함수들을
  • cath 메소드에는 오류 발생시 실행할 함수를 인자로 넣어주면 됨
  • 오래된 브라우저에서는 Fetch API가 지원되지 않을 수 있지만, 점점 더 많은 현대적인 웹 서비스에 Fetch API가 도입되고 있음
  • AJAX에 관련하여 강력한 기능 사용하고 싶다면 axios와 같은 외부 라이브러리도 좋은 선택지임
profile
최강 개발자를 꿈꾸는 병아리

0개의 댓글