보통 웹페이지를 구성할 때 정보들을 기억해야 할 때가 분명 존재한다. 간단한 텍스트부터 용량이 꽤 되는 파일까지 다양한 요소들이 있다. 이를 위해 당연히 외부 DB를 사용할 것이라고 생각하겠지만 간단한 정보를 위해 외부 DB에 접근해서 값을 찾아오는 것은 성능적인 부분에서 꽤 손해가 큰 경우가 많다. 그럴 때 사용하는 것이 웹 브라우저 내의 Storage
기능인 local storage, session 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
이 들어가지 않을까 싶다. 메서드는 local storage
와 동일하고, 생명주기 정도만 다르다고 인식하면 될 것 같다. 데이터가 갱신될 때는 storage
이벤트가 실행되는데, 종류는 다음과 같다고 한다.
key – 변경된 데이터의 키 ( .clear()를 호출했다면 null )
oldValue – 이전 값 ( 키가 새롭게 추가되었다면 null )
newValue – 새로운 값 ( 키가 삭제되었다면 null )
url – 갱신이 일어난 문서의 url
storageArea – 갱신이 일어난 localStorage나 sessionStorage 객체
DB
라는 이름이 붙은만큼 transaction
기능을 제공하는데, local storage
나 session storage
와 같이 client
입장에서 사용할 수 있는 client storage
형태로 사용하게 된다. 일반적인 DB와 다른 점이라면 B-Tree
구조를 형성하고 있고, NoSQL
즉 쿼리문을 사용할 수 없다. Object Store : DB의 테이블 역할
와 key, value
형태로 데이터들이 저장이 되며, 이를 고려해서 코드를 작성해야 한다. 부트캠프에서 인스타그램 클론 코딩을 진행했었는데, 사진과 데이터를 저장할 수 있는 공간이 필요해서 사용하게 되었다.
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
의 오픈 여부를 확인하는 것이고, databaseName
과 version
을 직접 변수로 등록해서 바로 인자값으로 넣을 수 있게 만들었다. 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에 업로드 된 모든 결과들을 화면에 출력해야 하는데, 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 loop
와 setAttribute
를 통해 각 데이터 타입의 객체들을 삽입해줘야 한다. data
에는 위에서 content와 image 값을 가지고 있었으므로 결과 창에서 보일 필요가 있는 image만 Attribute
해준다. 그리고 해당되는 위치에 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)를 설계해야 할 것 같다.
참고 링크