fetch로 데이터 받기 전 loading 상태

📅 TIL #148




🎯 Achievement Goals

fetch로 데이터 받기 전 상태와 받은 후의 상태를 알아본다.







Intro.

자바스크립트를 공부하다보면 fetch로 데이터를 받아서 렌더링을 해야되는 경우가 있다. fetch는 비동기 작업이고, DOM API를 통해 html을 조작한다면 빈 파일에서 부터 시작한다.


사용자가 웹 사이트에 들어왔을 때 빈 파일부터 보일 경우 UI가 매우 떨어진다. 이럴 경우 프론트엔드 개발자는 로딩 화면, 또는 로딩 이미지로 UI를 더 개선시킬 수 있다.


그리고 데이터를 통해 렌더링이 가능한 시점에 로딩 이미지를 없애고 화면을 구성할 수 있다.


오늘은 간단하게 fetch를 통해 데이터를 받기 전 로딩 메시지를 띄우고, Fulfilled 상태가 되면 화면을 렌더링하는 방식을 간단하게 블로깅하려고 한다.





fetch로 데이터 받기 전 상태와 받은 후의 상태를 알아본다.

fetch1


위 화면은 fetch를 통해 데이터를 요청하고 받아서 화면에 뿌려주었다. html은 DOM API를 조작했다. 그러면 Fulfilled된 시점에서 태그를 생성하고 태그에 데이터 값을 넣어준 후 렌더링이 성공적으로 끝난다.

데이터 요청 후 DOM 조작 코드는 다음과 같다.


// html
<div id="root"></div>

// JS
const root = document.getElementById('root');
const adress = 'https://jsonplaceholder.typicode.com/comments'
const DB = [];

async function render() {
  const res = await fetch(adress);
  const data = await res.json();
  DB.push(...data);

  DB.forEach((comment) => {
    const wrapper = document.createElement('div');
    wrapper.classList.add('comment-wrapper');

    const id = document.createElement('div');
    id.classList.add('id');
    id.textContent = comment.id;

    const name = document.createElement('div');
    name.classList.add('name');
    name.textContent = comment.name;

    wrapper.append(id, name);
    root.appendChild(wrapper);
  });


여기서 중요한 것은 브라우저의 렌더링 과정이다. 우리가 웹 사이트에 접속 시, 서버에 html 파일을 요청하고 받아 온 후 파싱을 한다. 파싱한 결과로 DOM Tree를 생성하는데, 현재 html파일은 root 셀렉터 하나만 존재한다. 데이터를 받아온 후 DOM을 조작할 예정이기 때문이다.


fetch-empty


그러면 위와 같이 파싱 후 잠시 빈 화면이 보였다가 렌더링이 될 것이다. 개발자는 UI를 더 개선하기 위해 로딩 메시지를 사용할 수 있다.


fetch-loading


위와 같이 빈 화면 보다는 loading 메시지를 띄웠다. 코드는 다음과 같다.


const root = document.getElementById('root');
root.textContent = "Loading...";

async function render() {
  try {
    const res = await fetch(address);
    const data = await res.json();
    DB.push(...data);
    if (DB.length > 0) {
      root.textContent = "";
    }
  } catch (err) {
    root.textContent = err;
  }


데이터를 받은 시점에 Loading 메시지를 없애주고 데이터를 통해 렌더링을 완료했다. 간단하게 textContent로 Loading 처리를 했지만, 이미지나 애니메이션을 통해서 로딩 화면을 구성할 수도 있다.


자바스크립트의 메인 쓰레드인 이벤트 루프는 싱글 쓰레드이다. 하지만 이벤트 루프가 독립적으로 실행되지 않고, 웹 브라우저나 NodeJS같은 멀티 쓰레드 환경에서 실행된다. 그래서 자바스크립트의 런타임은 싱글 쓰레드가 아니다.


자바스크립트는 싱글 쓰레드이지만, 런타임 환경은 싱글 쓰레드가 아니라는 말이 처음에는 굉장히 어려웠다. 싱글 쓰레드로 동작을 하지만 비동기 요청을 통해 여러 요청들을 처리할 수 있다는 개념이다.


먼저 실행이 가능한 함수들을 콜 스택에 담아 순차적으로 처리하다가, APIsetTimeout같은 비동기 작업은 잠시 Web API로 넘겨준다. 콜 스택에 있는 함수들의 처리가 끝나면 후에 이벤트 루프 과정을 통해 콜스택으로 넘겨서 처리한다.


오늘 사용한 fetch와 같은 웹 브라우저에서 제공하는 API같은 경우도 비동기 작업으로 실행한다. 여기서 fetch는 자바스크립트 엔진이 처리하는 것이 아니라, Web API가 처리한다. 그렇기 때문에 로딩 화면이 생겨난 것이다.


Web API로 넘긴 후 처리하는 과정에서 로딩 화면을 띄우고, 이벤트 루프를 통해 콜 스택으로 넘긴 후 데이터가 Fulfilled 상태가 됐을 경우 렌더링을 한다.


이러한 과정을 오늘 로딩 화면 구성을 통해 학습했다. 오늘은 간단하게 메시지로만 로딩 화면을 구성했지만, 로딩 화면을 구성하는 방법은 다양하다. 대표적으로 스켈레톤 로딩 방법도 있다.


스켈레톤 로딩을 통해서 데이터가 렌더링 되기 전에 앞으로 웹 사이트에 보여지는 화면의 윤곽을 미리 그려주는 로딩 애니메이션을 구현할 수 있다. 이를 통해 더 멋진 UI를 사용자에게 제공할 수 있다. 스켈레톤 로딩 구현도 공부해보면 아주 좋을 것 같다!