IndexedDB

CDD·2023년 3월 13일
0

web-develop

목록 보기
4/11
post-thumbnail

WEB Storage

보통 웹페이지를 구성할 때 정보들을 기억해야 할 때가 분명 존재한다. 간단한 텍스트부터 용량이 꽤 되는 파일까지 다양한 요소들이 있다. 이를 위해 당연히 외부 DB를 사용할 것이라고 생각하겠지만 간단한 정보를 위해 외부 DB에 접근해서 값을 찾아오는 것은 성능적인 부분에서 꽤 손해가 큰 경우가 많다. 그럴 때 사용하는 것이 웹 브라우저 내의 Storage 기능인 local storage, session storage 기능이다.

Local Storage

로컬 스토리지는 말 그대로 본인이 사용하고 있는 로컬 환경에 저장하는 방식이다. 세션을 종료하더라도 자료가 그대로 남고, 재활용에 용이하다는 장점이 있다. 크롬의 개발자 모드에서 Application - Local Storage로 들어가면 확인할 수 있고, 구현방식도 되게 간단하다.

localStorage.setItem('cdd', 'crazy');

이런식으로 값을 set 해줌으로써 local storage에 값이 저장된다. 여기서 값을 다시 꺼내오려면 다음과 같이 진행하면 된다.

const cat = localStorage.getItem('myCat');

메서드 종류는 다음과 같다.

- setItem(key, value) – 키-값 쌍을 보관
- getItem(key) – 키에 해당하는 값을 받아옴
- removeItem(key) – 키와 해당 값을 삭제
- clear() – 모든 것을 삭제
- key(index) – 인덱스(index)에 해당하는 키를 받아옴
- length – 저장된 항목의 개수를 얻음

하지만 이 방식은 브라우저마다 용량에 대한 제한이 있고, 그 제한이 15mb 정도라서 요즘의 고화질 이미지를 생각하면 1, 2장 정도로 끝나버리는 용량이다.

Session Storage

사실 세션 스토리지는 아직까지도 큰 필요성을 잘 못느끼고 있다. 탭을 닫으면 정보가 사라지고, 그렇기 때문에 이름에 Session이 들어가지 않을까 싶다. 메서드는 local storage와 동일하고, 생명주기 정도만 다르다고 인식하면 될 것 같다. 데이터가 갱신될 때는 storage 이벤트가 실행되는데, 종류는 다음과 같다고 한다.

key – 변경된 데이터의 키 ( .clear()를 호출했다면 null )
oldValue – 이전 값 ( 키가 새롭게 추가되었다면 null )
newValue – 새로운 값 ( 키가 삭제되었다면 null )
url – 갱신이 일어난 문서의 url
storageArea – 갱신이 일어난 localStorage나 sessionStorage 객체

IndexedDB

DB라는 이름이 붙은만큼 transaction 기능을 제공하는데, local storagesession storage와 같이 client 입장에서 사용할 수 있는 client storage 형태로 사용하게 된다. 일반적인 DB와 다른 점이라면 B-Tree 구조를 형성하고 있고, NoSQL 즉 쿼리문을 사용할 수 없다. Object Store : DB의 테이블 역할key, value 형태로 데이터들이 저장이 되며, 이를 고려해서 코드를 작성해야 한다. 부트캠프에서 인스타그램 클론 코딩을 진행했었는데, 사진과 데이터를 저장할 수 있는 공간이 필요해서 사용하게 되었다.

open IndexedDB

const request = indexedDB.open(databaseName, version);

데이터베이스 생성 방식은 다음과 같다. indexedDB.open 메서드에 인자값으로 데이터베이스의 이름과 버전이 들어간다.

shareBtn.addEventListener("click", function () {
  if (window.indexedDB) {
    const databaseName = "instagram";
    const version = 1;
    const request = indexedDB.open(databaseName, version);
    const data = {
      content: document.querySelector("modal__write > textarea").value,
      image: imageBase64,
    };
    request.onupgradeneeded = function () {
      request.result.createObjectStore("posts", { autoIncrement: true });
    };

    request.onsuccess = function () {
      const store = request.result
        .transaction("posts", "readwrite")
        .objectStore("posts");

      store.add(data);
    };
  }
});

위의 코드는 인스타그램 클론 코딩에서 shareBtn을 눌렀을 시에 대한 Event Listener인데, 전반적인 indexedDB 생성 구조를 살펴볼 수 있다. window.indexedDB 부분은 indexedDB의 오픈 여부를 확인하는 것이고, databaseNameversion을 직접 변수로 등록해서 바로 인자값으로 넣을 수 있게 만들었다. data 부분은 블록 스코프를 만들어서 내용(content)와 이미지(image) 형태로 저장할 수 있게 해두었고, onupgradeneeded에서는 키값을 자동으로 증가하게 해서 데이터들을 저장할 수 있게 해두었다. const store 부분은 request, 즉 indexedDB가 성공적으로 open 되었을 때 transaction을 생성하고 posts라는 이름의 objectStore을 생성한다. 마지막 add() 메서드는 data를 DB에 업로드하는 식이다.

종종 예외처리를 하지 않아 오류가 발생하는 경우가 있는데, 그런 경우 다음과 같은 코드를 작성해주면 해결할 수 있다.

request.onerror = (event) => {
  console.error("indexedDB error:", event.target.error);
}; // request 예외처리

else {
  console.error("indexedDB is not supported");
} // onsuccess 예외처리

IndexedDB 값 가져오기

그러면 이제 indexedDB에 업로드 된 모든 결과들을 화면에 출력해야 하는데, getAll() 메서드를 활용하면 된다.

store.add(data).onsuccess = function () {
              store.getAll().onsuccess = function (e) {
                const response = e.target.result;
                const mainPostsEl = document.querySelector('.main__posts');
                mainPostsEl.setAttribute('class', 'main__posts');
                document.querySelector('body').removeChild(modalEl);
                mainPostsEl.innerHTML = '';
                for (let i = 0; i < response.length; i++) {
                  const postListEl = document.createElement('img');
                  postListEl.setAttribute('src', response[i].image);

                  document
                    .querySelector('.main__posts')
                    .appendChild(postListEl);
                }
              };

getAll() 메서드를 이용하면 e.target.result을 통해 모든 값들을 가져올 수 있다. 그렇다고 바로 쓸 수 있는게 아니고, for loopsetAttribute를 통해 각 데이터 타입의 객체들을 삽입해줘야 한다. data에는 위에서 contentimage 값을 가지고 있었으므로 결과 창에서 보일 필요가 있는 imageAttribute 해준다. 그리고 해당되는 위치에 appendChild() 해주면서 화면에 출력하는 식이다. 다른 식의 출력 같은 경우에도 값을 가져오고 사용할 부분의 value 값을 가져와 append() 해줄 수 있다. 특정 값만 가져오고 싶다면 다음과 같은 방법을 사용할수도 있다.

db.transaction("customers").objectStore("customers").get("444-44-4444").onsuccess = function(event) {
  alert("Name for SSN 444-44-4444 is " + event.target.result.name);
};

정말 솔직히 얘기하자면 요즘은 하드웨어 성능이 워낙 좋아져서 외부 DB를 사용할 때도 그렇게 성능 저하가 느껴지지 않는다. 사용환경이 달라질 때 데이터가 유지되지 않는다는 단점도 있고, 정말 성능을 극대화 할 일이 아니라면 크게 사용할 일이 없을 것 같기는 하다. 다만 유저 개인의 데이터들을 출력하는 것이 주목적인 소프트웨어라면 다시 글을 참고하면서 indexedDB(노후화된 DB)를 설계해야 할 것 같다.

참고 링크

0개의 댓글