브라우저의 로컬스토리지와 세션스토리지는 굉장히 편리한 수단이죠. 간단한 데이터를 브라우저에 저장하고 언제든 손쉽게 꺼내쓸 수 있습니다.

복잡하고 장황한 코드도 필요 없습니다. 한 줄이면 쉽게 처리 가능하죠.

아래처럼요.


localStorage.setItem(storageName, JSON.stringify(storageData));

localStorage.getItem(storageName, JSON.stringify(storageData));

하지만, 구글 개발팀은 더 이상 사용을 권장하지 않는군요.

구글은 로컬스토리지보다는 캐시API나 IndexedDB를 사용할 것을 권장하고 있습니다.

물론, 구글과 모질라가 서비스워커를 주도적으로 개발했고, 캐시API는 서비스워커가 제공하는 기능이므로 구글이 캐시API 사용을 권장하는 것은 이해됩니다.

캐시API는 사용이 어렵지 않습니다. 하지만, 로컬스토리지만큼 사용이 편리하지도 않습니다. 간단한 데이터를 저장한다면 여전히 로컬스토리지가 강점이 있습니다.

하지만, 아래와 같은 단점도 있습니다.

  • 용량 제한이 있다. (사파리 5MB, 크롬/엣지/파이어폭스/오페라 10MB)

  • 메인 스레드에서 동작하므로 읽고 쓰는 동안 관련 UI가 멈춘다.

조금 더 복잡하고 용량이 큰 데이터라면 캐시API나 IndexedDB를 사용하는 것이 낫습니다. 특히, css와 js, image 등의 정적인 자원은 캐시API를 활용해 서버 요청을 줄이면 더 쾌적한 환경을 제공할 수 있습니다.

웹 저장소 개요

캐시API와 indexedDB에 대해 설명하기 전에 다양한 웹 저장소의 특징을 먼저 간략히 정리해보겠습니다.

먼저, 저장소를 분류할 수 있는 간략한 특징들을 먼저 열거해 보겠습니다.

1) 데이터 모델

  • 구조적: 전형적인 SQL 기반 데이터베이스 관리 시스템과 마찬가지로, 데이터를 구조적으로 저장할 수 있도록 해주고 쿼리 및 수정 등의 작업도 가능하게 합니다. 대표적으로는 IndexedDB가 있습니다.

  • 키/값: 키/값 데이터 저장소는 고유한 키로 색인이 생성된 구조화되지 않은 데이터를 저장합니다. 대표적으로는 Cache API가 있습니다.

  • 바이트 스트림: 데이터를 가변 길이의 바이트 문자열로 저장합니다. 파일 시스템API가 대표적입니다.

2) 동기/비동기

일부 웹 저장소API는 저장 또는 검색 작업을 수행할 때, 현재 활성 스레드에서 수행되면서, 활성 스레드의 다른 작업이 모두 정지됩니다. 이런 의미에서 동기적입니다. 이는 그리드와 같이 복잡하고 빈번한 DOM 변경 작업을 수행하는 경우 부담이 될 수 있습니다. 캐시 API와 IndexedDB의 경우 현재 활성 스레드가 아닌 별도의 스레드에서 수행됩니다. 이런 의미에서 비동기적입니다.

3) 트랜잭션

일부 저장소API는 트랜잭션으로 그룹화 합니다.

저장소 비교

자, 그러면 각 저장소들의 특징을 간략히 비교해 봅시다.

API 데이터 모델 트랜잭션 동기/비동기 단점
File System 바이트 스트림 아니요 비동기 Chromium 기반 브라우저만 지원
Local Storage 키/값 아니요 동기 용량 제한(5MB, 10MB), 동기식
Session Storage 키/값 아니요 동기 용량 제한(5MB, 10MB), 동기식
Cookies 구조적 아니요 동기 웹 워커에서 접근 불가
Cache API 키/값 아니요 비동기  
IndexedDB 하이브리드 비동기 복잡함

위 표에서 IndexedDB는 데이터모델이 하이브리드로 명시되어 있는데, 이는 구글 개발자사이트의 표기를 따른 겁니다. IndexedDB는 구조적 데이터모델을 따르지만, 데이터 객체 안에 키/값 쌍으로 된 데이터 레코드를 사용하므로 하이브리드로 명시한 듯합니다.

File System은 Chromium 기반이라 범용적으로 사용하기 원한다면 쓰지 않아야 합니다. 저 역시 File System은 써본 적이 없습니다. 사실, 써보고자 하는 의지도 가진 적이 없습니다.

Cookies는 본연의 역할이 있기 때문에 저장소로 사용하지 않는 것이 좋습니다. 또한, Cookies는 문자열만 저장할 수 있습니다.

캐시 API

Cache API는 서비스워커에서 제공하는 것으로 네트워크로 불러 온 리소스 파일을 캐싱할 수 있습니다.

Cache API는 기존의 브라우저 캐시와는 다릅니다. 브라우저 캐시는 브라우저에 한 덩어리로 관리되죠. 개발자가 컨트롤 할 방법이 없습니다. 기존의 http 캐시와는 달리, 캐시 API는 여러 캐시 객체를 가질 수 있으며, 이 캐시 객체를 통해 캐시를 세밀하게 관리할 수 있습니다.

이미지 전용 캐시, js 전용 캐시 하는 식으로 말이죠. 그 외에도 세부적인 항목을 정해서 얼마든지 새로운 캐시를 만들어 관리할 수 있습니다.

네트워크에서 불러오는 이미지나 css, js 등의 정적인 리소스는 캐시 API로 관리하는 것이 좋습니다.

캐시 API는 서비스워커를 통해 접근할 수 있습니다.

IndexedDB

네트워크로 불러 온 정적 리소스가 아니라, 수시로 변해야 하는 데이터라면 indexedDB가 적당합니다.

indexedDB는 브라우저에 데이터베이스를 구축하는 것입니다. 트랜젝션 모델을 사용합니다.

미리 정의된 데이터 열과 행으로 이루어진 테이블 기반의 데이터베이스와는 달리 Javascript 기반의 객체지향 데이터베이스입니다.
데이터베이스 안에 여러 개의 객체 저장소가 있고, 그 객체 저장소에는 키(key)-값(value) 쌍으로 된 레코드가 들어있는 식입니다.

명칭에서도 알 수 있듯이 인덱스를 사용해 객체 저장소를 쿼리할 수 있고, 쿼리와 매칭되는 레코드만 순회하여 탐색할 수 있습니다.
물론, WHERE문을 통해 아무 열이나 쿼리할 수 있는 SQL문과는 달리, 오직 객체 저장소의 인덱스 혹은 미리 정의한 객체 키만 쿼리할 수 있습니다.

IndexedDB는 개념은 간단하지만 사용이 복잡하기로 악명이 높았습니다. 하지만, IndexedDB를 효과적으로 사용할 수 있도록 도와주는 많은 라이브러리들도 나와 있어서 점점 더 많이 쓰이는 추세입니다.

IndexedDB 라이브러리는 MDN 사이트 하단을 참조하시면 됩니다.

용량

사용 가능한 용량은 어떻게 될까요?

로컬스토리지와는 비교도 안되게 많은 용량을 저장할 수 있습니다. 사파리를 제외한 모던 브라우저에서는 용량을 수치로 제한하지 않습니다. 사용자 디바이스의 저장 용량에 따른 제한만이 있습니다.

브라우저 용량
Chrome - 사용자 디스크 용량의 60%
- StorageManage API를 활용해 저장할 수 있는 최대 용량을 확인할 수 있습니다.
Edge 크로미움 엔진 기반이라 Chrome과 동일합니다.
Firefox 빈 디스크 용량의 50%까지 저장할 수 있습니다.
Safari 1GB까지 저장할 수 있습니다. 용량을 다 쓰면 허용 용량을 200MB 더 늘릴 것인지 물어보는 팝업이 생성됩니다.

웹 저장소 API를 비교해 보면, Local Storage와 Session Storage는 용량의 한계 때문에 커다란 규모의 데이터를 저장할 때는 적절치 않습니다. 현재 활성화 된 스레드에서 실행되므로, 복잡한 UI를 다룰 때도 난감한 점이 있습니다. 물론, 사용이 쉽다는 장점이 있으므로 간단한 데이터는 여전히 Local Storage와 Session Storage를 쓰셔도 좋습니다.

=================

저는 최신 프로젝트에 캐시API를 적용해 진행하고 있습니다.

지도 서비스와 같은 대용량 이미지 뷰어를 제작해야 하는데요. 구글의 지도 서비스와 같은 맥락이라고 보시면 될 것 같습니다.

대용량의 이미지이지만 사용자는 이 대용량의 이미지를 매우 빠르게 로드하고 드래그 및 확대/축소해 보길 원합니다.

답은 이미지를 아주 작게 조각내서 타일 이미지 맵을 만들 것입니다. 아래 그림과 같이 말이죠.

이미지타일 개념도

잘라진 타일 이미지는 브라우저 캐시에 저장할 것입니다. 그리고, 사용자가 이미지를 드래그 및 확대/축소할 때 서버로의 요청을 최대한 자제하고 캐시에 미리 저장된 이미지를 브라우저에 로드하는 식으로 제작하는 방법을 고려하고 있습니다.

IndexedDB까지 쓸 일은 없을 것 같네요.

과거 Angular로 적용된 프로젝트는 애플리케이션을 실행하면 정적인 리소스를 다운로드 받는 시간 동안 Loading 문구를 띄워놓곤 했는데요. 서비스워커를 통해 js파일과 css, image 등의 정적 리소스를 모두 캐시API로 처리했더니 애플리케이션 실행이 훨씬 쾌적해졌습니다.

대용량 이미지 처리 부분은 이보다 훨씬 복잡한 처리가 필요할 것 같지만 성능 문제를 일부 보완하는 긍정적인 효과를 낼 것으로 기대하고 있습니다.

대용량 이미지 뷰어에 대한 캐시API 사용 경험은 프로젝트 완료 후 기회가 되면 다시 포스팅하도록 하겠습니다.

참조

1) Storage for the web
2) 웹 저장소 개요
3) MDN IndexedDB