dankthedust 2021. 8. 15. 17:53

JavaScript의 발전으로 정적 웹에서 동적 웹페이로, 그리고 문서적인 성향에서 어플리케이션 적인 성향으로 발전했다.

하지만 언제나 그렇듯 불만이 있었는데, 그 요인으로는 페이지의 변동사항이 있을 경우, 부가적인 수정소요가 많다는 것이다.

페이지의 변동사항이 있을 경우, 다시 웹 페이지 전체를 리로드해야 하고 업데이트 해야한다. 이런 경우 페이지와 서버와의 통신량이 방대해지고 사용자 또한 매번 리로드 되는 경험을 해야할 것이다.

개발자는 수정요소가 있어 변경할 때에 메인 페이지에 수정을 한다하고 그와 연관된 페이지가 무수히 많다면 그 페이지들을 모두 수정하는 불필요한 개발시간을 투자해야한다라는 것이다.

이러한 불편을 해소해주는 기능이 Ajax이며, 하나의 페이지에 정보를 담고 리로드 없이 업데이트를 해주며 정보를 보여주는 기능을 하는 페이지를 SPA(Single Page Application)이라고한다.

AJAX는 Asynchronous Javascript And Xml의 줄임말로 비동기식 JavaScript와 XML을 말한다.

  • 자바스크립트를 통해 서버와 브라우저가 비동기 방식으로 데이터를 교환할 수 있는 통신기능
  • 브라우저가 가지고 있는 XMLHttpRequest 객체를 이용해서 페이지의 일부를 리로드 하는 기법

비동기 방식(Asynchoronous)를 쉽게 얘기해자면, 동기식은 일처리를 순차적으로 각 세부의 일들을 해나가는 방식이고 비동기식은 여러 세부 일들을 각기 시작하며, 독립적으로 본다라고 할 수 있다.

https://velog.io/@surim014/AJAX%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80

이처럼 AJAX는 보여주고자 하는 정보를 server를 통해서 제공하는 방식인데, 이런 경우 페이지의 제작이 단순명료 해지며 양이 적어지지만 단점으로는 google, naver 등의 검색엔진에서는 상당히 제한된다는 것이다.

그 이유로는 검색엔진은 페이지를 다운받아서 정보를 제공하는데, AJAX의 경우에는 페이지 자체에 정보를 내장하고 있지 않고 백엔드 즉, server에 그 내용을 저장하고 있는 형태이기 때문이다.


Ajax의 여러 사용 방법 중에는 여러가지가 있지만 해당 수업에서는 fetch API를 사용했다.

fetch API의 요청과 응답

<!DOCTYPE html>
<html lang="en">
    <body>
        <article>

        </article>
        <input type="button" value="fetch" onclick="
            fetch('fileName').then(function(response){
                response.text().then(function(text){
                    document.querySelector('article').innerHTML=text;
                })
            })
        ">
    </body>
</html>

위의 예제에서 fileName이라고 하는 것은 내가 불러오고자 내용이 담긴 파일의 이름을 의미한다.

즉, fileName이라는 파일의 내용을 불러와 <article>에 내용을 추가하는 함수가 담긴 button이 해당 페이지의 기능이다.

여기서 Ajax의 특성인 비동기식 실행이 보이는데, 이는 then()이라는 함수 때문이다.

fetch('fileName'); //server에 이름이 fileName인 파일을 요청

function callBackMe(){
	console.log('response end');
}
fetch('fileName').then(callBackMe); //fileName 파일이 요청되어 server가 응답하면(then), 함수 callBackMe를 실행시켜라
console.log(1);
console.log(2);

// then이라는 함수는 fetch('fileName')이 완료가 된 시점에 실행이 되며, 완료 이전에는 다음의 코드가 비동기적으로 실행된다

아래 사진과 같이 console.log(1)과 console.log(2)가 먼저 실행된 이후에 callBackMe 함수가 실행되는 것을 확인할 수 있다. 즉, then()을 통해서 fetch('fileName')의 실행이 끝난 이후에 실행이되며, 이러한 방식을 비동기라고 한다.

fetch API - response 객체

fetch('fileName').then(function(response){
	console.log(response);
});

다음의 코드를 실행 했을 때의 console창의 출력내용이다.

Response 객체는 server로 부터 요청 받은 fileName이라는 파일의 상태, 정보들을 나타대어 주는 객체이며, 이를 통해서 우리는 응답 상태(status) 등을 확인이 가능하고 예제처럼 response.text()를 통해서 fileName내에 있는 내용(정보)를 얻을 수 있다.


위의 fetch를 예제에 적용하면 다음과 같다.

<!doctype html>
<html>
<head>
  <title>WEB1 - Welcome</title>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="colors.js"></script>
</head>
<body>
  <h1><a href="index.html">WEB</a></h1>
  <input id="night_day" type="button" value="night" onclick="
    nightDayHandler(this);
  ">
  <ol>
  	<!-- <li><a href="1.html">HTML</a></li>
    <li><a href="2.html">CSS</a></li>
    <li><a href="3.html">JavaScript</a></li> -->
    
    <li><a onclick="fetchPage('html')">HTML</a></li>
    <li><a onclick="fetchPage('css')">CSS</a></li>
    <li><a onclick="fetchPage('JavaScript')">JavaScript</a></li>
  </ol>
  <article></article>
</body>
<script>
  function fetchPage(fileName){
    fetch(fileName).then(function(response){
      response.text().then(function(text){
        document.querySelector('article').innerHTML=text;
      })
    })
  }
</script>
</html>

주석처리한 부분과 같이 1,2,3의 페이지를 로드하던 것과는 달리 index.html 하나의 페이지에서 3개의 내용을 담아와 <article> 내에 업데이트를 하며 통신량과 리로딩의 불편함을 해소했다.


fragment identifier를 이용한 초기 페이지 기능 구현

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <a href="#three">three</a>
    <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius ipsa atque consequuntur ea dicta accusamus illo exercitationem accusantium, maxime iure adipisci sint nihil illum eligendi, voluptas debitis. Nulla tempora aliquam odit laborum! Architecto at nam veniam, culpa perferendis deleniti voluptatum dolorum aliquid doloribus sunt error laboriosam nihil qui quis modi incidunt itaque, alias atque, quasi dicta. Tempore, corporis cum sit praesentium assumenda voluptas nulla expedita repudiandae, unde officia odio reiciendis nostrum. Debitis a fuga nam explicabo voluptate nulla aut voluptatem natus nostrum unde ipsam, facilis animi magnam suscipit adipisci ut incidunt laborum inventore esse est nobis corrupti. Aperiam, nostrum hic!
    </p>
    <p>
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Debitis temporibus culpa asperiores ad similique. Laudantium fuga inventore necessitatibus quasi animi. Quo velit maiores, nisi qui illo officiis enim consequuntur exercitationem nobis nam ipsum est hic mollitia doloribus. A alias aspernatur nihil mollitia esse earum officia nisi doloribus veritatis perferendis odit autem suscipit nemo quis repellendus, provident commodi natus, ducimus consequatur optio, consequuntur eaque cupiditate! Repudiandae architecto alias at voluptas ex soluta ratione vitae cupiditate unde repellat fugit sit, libero perferendis aliquid doloribus quis est voluptatibus consequuntur provident error nihil? At porro blanditiis facilis illo modi adipisci tempora iusto sit officiis.
    </p>
    <p id="three">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Ad perspiciatis, dolores libero in labore quia ipsa ullam consequuntur excepturi reprehenderit doloribus sint ea voluptate, iste voluptatibus ab. Ipsa earum asperiores ab atque rerum, non temporibus. Nihil eos libero nobis sunt odit assumenda iure, dignissimos mollitia voluptates totam quod fugit fugiat soluta dolorem beatae accusantium temporibus delectus laboriosam aut error ullam saepe ut architecto! Voluptatibus facilis temporibus, rem, quisquam doloremque dolorum quibusdam laudantium animi inventore reiciendis nulla earum assumenda mollitia fugiat eveniet esse aspernatur voluptatem. Vel illo laborum consequuntur possimus, debitis, ducimus iusto dolorem voluptas obcaecati nostrum ratione, cum laudantium mollitia.
    </p>
</body>
</html>

라는 hash.html 페이지를 만들었을 때 <a>태그를 클릭하게 되면 id값이 three인 문단으로 이동을 하게 되며, url주소 역시 hash.html#three로 변경이 된다.(리로드는 없다.)

다음과 같은 three를 url의 hash(해쉬)라고 부르며 우리는 이 값을

console.log(window.location.hash); //#three
console.log(window.location.hash.substr(1)); //three

를 통해서 얻을 수 있다.

hash(해쉬)를 통해서 url주소의 차이를 주어 공유 등의 사용자에게 편의성을 제공하자면 다음과 같다.

<!doctype html>
<html>
<head>
  <title>WEB1 - Welcome</title>
  <meta charset="utf-8">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <script src="colors.js"></script>
</head>
<body>
  <h1><a href="#welcome">WEB</a></h1>
  <input id="night_day" type="button" value="night" onclick="
    nightDayHandler(this);
  ">
  <ol>
    <li><a href='#!html' onclick="fetchPage('html')">HTML</a></li>
    <li><a href='#!css' onclick="fetchPage('css')">CSS</a></li>
    <li><a href='#!javascript' onclick="fetchPage('JavaScript')">JavaScript</a></li>
  </ol>
  <article></article>
</body>
<script>
  function fetchPage(fileName){
    fetch(fileName).then(function(response){
      response.text().then(function(text){
        document.querySelector('article').innerHTML=text;
      })
    })
  }
  if(location.hash){
    fetchPage(location.hash.substr(2));
  } else {
    fetchPage('welcome');
  }
</script>
</html>

현재에는 hash(해쉬)를 이용한 방법보다 단점을 보안한 pjax를 사용한다.


글목록

예제의 마무리로 카테고리의 list를 쉽게 추가하고 제어할 수 있도록 글목록을 수정한다.

list라는 파일에 글목록들을 작성(html,css,javascript)하여 저장해주고 해당 목록을 javascript를 통해 불러와 id가 nav인 태그에 출력되도록 해보자.

<!-- list file -->
html,css,javascript
<body>
  <ol id='nav'>
  </ol>
</body>
<script>
  fetch('list').then(function(response){
      response.text().then(function(text){
        var listItem = text.split(',');
        var i=0;
        var tags ='';
        while(i<listItem.length){
          var item = items[i];
          //<li><a href="#!html" onclick="fetchPage('html')">html</a></li>
          var tag = '<li><a href="#!'+item+'" onclick="fetchPage(\''+item+'\')">'+item+'</a></li>';
          tags+=tag;
          i+=1;
        }
        document.querySelector('#nav').innerHTML =text;
      })
  })
</script>

다음과 같이 작성하였다. 여기서 \' 는 '가 문자와 코드를 구분하는 구분자 역할이 아닌 문자의 역할임을 컴퓨터가 알 수 있도록 \(역슬래시)를 ' 앞에 붙이는 것이다.


fetch API를 사용하면서 확인하여야 하는 것은 웹 브라우저의 호환성이다.

개발자는 클라이언트의 사양에 맞추어 해당 기능이 정상적으로 구동될 수 있도록 지원해줘야 한다.

caniuse.com을 통해서 호환성을 살펴보면

fetch API의 호환성 <caniuse.com>

다음과 같이 IE는 모두 제한되고 Edge브라우저의 경우는 12-13버전은 지원을 하지 않는 등의 제한이 생긴다.

이때, polypill을 이용하면 fetch API를 지원하지 않는 웹브라우저에서도 이용할 수 있다. 지원되지 않는 브라우저에서 코드가 실행되면 polyfill 이 활성화되서 대신 동작하게 된다.