인터넷 연결은 시시때때로 끊길 수 있고 불안정하므로, PWA에서는 오프라인 환경과 신뢰할 수 있는 성능을 안정적으로 제공하는 것이 필수다. 또한 완벽히 온라인 환경이 제공된다 하더라도, 캐싱과 다른 스토리지 기술을 적절히 활용한다면 사용자의 경험을 향상 시킬 수 있다. 정적 애플리케이션 리소스(HTML, Javascript, CSS)와 데이터 (사용자 데이터, 뉴스 기사 등)를 캐싱하는 방법이 꽤 있다. 어떤 것이 가장 좋은 해결책이며, 이들은 얼마나 저장할 수 있을까?
이 두 방식은 모두 모던 브라우저에서 지원한다 (IE 제외). 그리고 둘다 비동기로 이루어지며 메인스레드를 블로킹하지 않는다. 또한 window
, 웹 워커, 서비스 워커에서 접근 가능 하기 때문에 어디서든 사용하기 쉽다.
물론 이 외에도 브라우저에서 사용할 수 있는 다른 스토리지가 존재한다. 그러나 이들은 사용에 제한이 있으며, 성능적인 문제 또한 존재한다.
몇 백 메가바이트, 그리고 잠재적으로 수백 기가바이트 이상이 될 수도 있다. 브라우저 별로 다를 수 있지만, 사용가능한 스토리지의 크기는 대개 장치에서 사용 가능한 스토리지의 크기에 따라서 결정된다.
eTLD+1
(effective Top Level Domain) 의 경우에는 최대 2GB까지 가능하다. StorageManager API를 통해서 얼마나 사용가능한지 확인할 수 있다.과거 스토리지 용량 최대치에 근접하게 되면, 브라우저는 사용자에게 메시지를 띄워서 권한을 획득한 후, 추가로 스토리지용량을 제공했다. 그러나 요즘 모든 브라우저는 사용자에게 특별히 메시지를 띄우지 않고 최대 사용량 까지 사용하게 해준다. 사파리의 경우는 조금 다르다. 앞서 이야기 한것처럼 추가 할당량 사용여부를 유저에게 묻고 허락할 경우 사용하게 해주지만, 그 이상은 불가능 한 것으로 보인다.
Storage Manager API를 통애서 확인 가능하다.
if (navigator.storage && navigator.storage.estimate) {
const quota = await navigator.storage.estimate()
const percentageUsed = (quota.usage / quota.quota) * 100
const remaining = quota.quota - quota.usage
console.table(quota)
}
index | value | caches | indexedDB | serviceWorkerRegistrations |
---|---|---|---|---|
quota | 299977904946 | |||
usage | 621244075 | |||
usageDetails | 620952837 | 256156 | 35082 |
Storage Manager API가 모든 브라우저에서 사용가능한 것은 아니므로, feature detect를 꼭 걸어줘야 한다. 또한 quota를 넘는 경우 에러가 발생할 수도 있으므로, try.. catch
로 이를 잡아 주는 처리를 해야 한다.
중요한 점은 코드를 작성할 시에 QuotaExceededError
와 같은 에러에 대해 염두해 두어야 한다는 것이다. IndexedDB 와 Cache API 모두 사용량 초과시에 DOMError
나 QuotaExceededError
를 던진다.
데이터 사용량을 초과한다면, IndexedDB
에 쓰려는 시도는 모두 실패한다. 트랜색션의 onabort()
가 호출된다. 여기에는 DOMException
이 포함된다. 에러의 name
을 확인하면 QuotaExceededError
가 보일 것이다.
const transaction = idb.transaction(['entries'], 'readwrite')
transaction.onabort = function (event) {
const error = event.target.error // DOMException
if (error.name == 'QuotaExceededError') {
// Fallback code goes here
}
}
try {
const cache = await caches.open('my-cache')
await cache.add(new Request('/sample1.jpg'))
} catch (err) {
if (error.name === 'QuotaExceededError') {
// Fallback code goes here
}
}
최대 용량 초과로 인해 데이터가 지워지는 것을 의미한다.
웹 스토리지는 Best Effort
와 Persistent
두개의 버켓으로 구분할 수 있다. Best Effort
란 스토리지가 사용자를 방해하지 않고 브라우저에 의해 정리될 수 있다는 것을 의미하는데, 이는 중요한 데이터에 적합하지 않다는 것을 의미한다. Persistent
스토리지는 저장가용량이 낮더라도 자동으로 삭제 되지는 않는다. 사용자가 수동으로 데이터를 삭제 해야 한다.
기본적으로, 사이트의 데이터는 Best Effort
로 분류되어 사이트가 별도로 persistent storage를 요청하지 않는다면, 가용량이 낮아지게 되면 자동으로 데이터를 삭제하게 된다.
best effort
내에서 eviction 정책은 아래와 같다.
iOS, iPadOS 13.4, 맥의 safari 13.1 부터, Cache API, indexed DB, storage 등의 쓰기 스토리지에 대해서 7일간의 제한을 걸어두기 시작했다. 이는 사용자가 사이트에서 인터랙션을 하지 않을 경우, 사파리가 7일 이후에는 캐시에서 모든 데이터를 제거한다는 것을 의미한다. 이 정책은 홈스크린에 설치된 PWA에는 적용되지 않는다. 자세한 내용은 여기를 참조!
IndexedDB는 저수준 API로, 아주 작은 양의 데이터를 저장하는데 사용한다 할지라도 처음 설치에 있어 많은 심혈을 기울여야 한다. 다른 모든 promise 기반 API와는 다르게, 이벤트 베이스로 작동된다. idb를 사용하면 일부 강력한 기능을 사용할수 없지만 트랜잭션과 스키바 버전과 같은 복잡한 기능을 사용하지 않더라도 promise 기반의 indexeddb를 사용할 수 있게 해준다.