history API 구조에 대한 호기심
until 에디터 테스트 겸 작성해보는 history 웹 API에 대한 간단한 포스트
헤헷 썸네일 등록이 안 되네
✅ 발단
history 웹 API를 이용한 SPA 구현
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<!-- 네비게이션 메뉴 -->
<!-- data-url 속성을 사용하여 각 페이지의 식별자 저장 -->
<ul>
<li>
<a href="/" data-url="home">Home</a>
</li>
<li>
<a href="/about" data-url="about">About</a>
</li>
<li>
<a href="/contact" data-url="contact">Contact</a>
</li>
</ul>
<!-- 페이지 컨텐츠가 표시될 영역 -->
<div id="page">Home 페이지입니다.</div>
<script>
// BOM(Browser Object Model)의 주요 객체들:
// - history: 브라우저의 방문 기록을 관리
// - Screen: 사용자의 화면 정보를 제공
// - Location: 현재 URL 관련 정보와 메서드를 제공
// 각 페이지의 컨텐츠를 저장하는 객체
const pages = {
home: "Home 페이지입니다.",
about: "About 페이지입니다.",
contact: "Contact 페이지입니다. <input text='text' placeholder='연락처 입력 하세요' />",
};
// 모든 네비게이션 링크 요소를 선택
const aEls = document.querySelectorAll("a");
// 각 링크에 클릭 이벤트 리스너 추가
aEls.forEach((aEl) =>
aEl.addEventListener("click", function (e) {
// 링크의 기본 동작(페이지 이동) 방지
e.preventDefault();
// 클릭된 링크의 data-url 속성값 가져오기
const page = e.currentTarget.dataset.url;
// History API를 사용하여 새로운 상태 추가
// pushState(상태객체, 제목(미사용), URL)
history.pushState({ page: page, custom: "test" }, "", `/${page}`);
// 페이지 컨텐츠 업데이트
document.getElementById("page").innerHTML = pages[page];
})
);
// 브라우저 뒤로가기/앞으로가기 처리
window.addEventListener("popstate", function (event) {
// 상태가 없는 경우 기본값으로 'home' 사용
// ?. 는 옵셔널 체이닝으로, event.state가 null/undefined일 때 에러 방지
const page = event.state?.page || "home";
// 현재 상태 로깅 (디버깅용)
console.dir(event.state?.page || "home");
console.log("뒤로가기 또는 앞으로 가기가 눌렸음");
// 페이지 컨텐츠 업데이트
document.getElementById("page").innerHTML = pages[page];
});
</script>
</body>
</html>
// 코드 출처 : 수코딩
🧐 궁금한 점
1. history API는 스택 구조인가?
https://developer.mozilla.org/ko/docs/Web/API/History
공식 문서를 보면 push와 pop으로 추가하고 제거하는 형태임을 알 수 있다. 이런 방식은 배열에서 주로 사용되므로, history 데이터가 스택 구조로 저장되는지 궁금했다.
이 부분에 대해 조사해 본 결과, history API는 연결 리스트 구조를 가지고 있지만 뒤로가기/앞으로가기는 스택 구조와 유사하게 동작한다고 정리할 수 있었다.
그리고 여기서 또 다른 질문이 생겼다.
2. 스택처럼 동작한다면 왜 배열로 구현하지 않았을까?
배열이 연결리스트보다 용량 차지가 적고, 배열처럼 동작할건데 왜 연결리스트로 구현했을까?
단순히 메모리 차지 용량을 비교한다면 연결리스트보다 배열이 유리한 게 맞다. 하지만 배열은 메모리 공간을 연달아 차지한다. 하지만 연결리스트는 포인터가 있기 때문에 메모리에 분산해서 저장할 수 있다.
마치 테트리스를 하는 상황과 같다.
포인터가 5칸짜리 막대 블럭이라면 메모리는 1칸짜리 블럭 5개인 셈이니 메모리를 훨씬 유연하게 사용할 수 있다.
이 때 공부했던 내용이 머리를 스치고 지나갔다…! 고마워요 CS 50🥲
브라우저의 가용 메모리는 충분하므로, 배열 형태를 사용해서 얻는 이점(메모리 공간 절약)보다, 그보다 조금 더 큰 연결 리스트 형태를 사용하는 것이 여러 모로 이득이었을 것이다.
연결리스트를 사용하면 동적 할당과 해제가 가능하고, 중간 삽입과 삭제가 가능하다. (그리고 가비지 컬렉션 면에서도 더 효율적이라고 한다!)
결론
사실 정확한 정보는 아직 찾지 못했다. 여러 문서를 뒤져보고 할루시네이션이 가장 적은 AI라는 퍼블렉시티한테도 물어봤지만 명확한 답변은 얻지 못했다. 짐작해 보자면 History API는 웹 API니까 브라우저 엔진마다 조금씩의 차이가 있기 때문에 문서별로 기재해 둔 정보의 차이가 있는 것 같다.
명확한 결론을 내지는 못 했지만, 뭔가에 호기심을 가지고 탐구해봤다는 점에 점수를 주기로 했다.