사용 가능한 저장공간 예측

제프 포스닉
제프 포스닉

tl;dr

더 많은 브라우저가 추가될 예정인 Chrome 61에서는 이제 웹 앱에서 사용 중인 저장용량과 사용 가능한 저장용량을 예측하여 표시합니다.

if ('storage' in navigator && 'estimate' in navigator.storage) {
  navigator.storage.estimate().then(({usage, quota}) => {
    console.log(`Using ${usage} out of ${quota} bytes.`);
  });
}

최신 웹 앱 및 데이터 저장소

최신 웹 애플리케이션의 저장소 요구사항을 고려할 때 저장되는 내용을 두 가지 카테고리로 나누면 도움이 됩니다. 하나는 웹 애플리케이션을 로드하는 데 필요한 핵심 데이터와 애플리케이션이 로드된 후 의미 있는 사용자 상호작용에 필요한 데이터입니다.

웹 앱을 로드하는 데 필요한 첫 번째 데이터 유형은 HTML, 자바스크립트, CSS 및 이미지로 구성됩니다. 서비스 워커Cache Storage API와 함께 이러한 핵심 리소스를 저장하고 나중에 이를 사용하여 웹 앱을 빠르게 로드하여 이상적으로 네트워크를 완전히 우회하는 데 필요한 인프라를 제공합니다. (새 Workbox 라이브러리나 이전 sw-precache과 같이 웹 앱의 빌드 프로세스와 통합되는 도구는 이러한 유형의 데이터 저장, 업데이트 및 사용 프로세스를 완전히 자동화할 수 있습니다.)

하지만 다른 유형의 데이터는 어떨까요? 이는 웹 앱을 로드하는 데 필요하지 않지만 전반적인 사용자 환경에서 중요한 역할을 할 수 있는 리소스입니다. 예를 들어 이미지 편집 웹 앱을 작성하는 경우 사용자가 버전 간에 전환하고 작업을 실행취소할 수 있도록 이미지의 로컬 사본을 하나 이상 저장하는 것이 좋습니다. 또는 오프라인 미디어 재생 환경을 개발하고 있다면 오디오 또는 동영상 파일을 로컬에 저장하는 것이 매우 중요합니다. 맞춤설정이 가능한 모든 웹 앱은 결국 어떤 종류의 상태 정보를 저장해야 합니다. 이러한 유형의 런타임 저장소에 사용 가능한 공간은 어떻게 알 수 있으며 공간이 부족하면 어떻게 해야 할까요?

이전 날짜: window.webkitStorageInfonavigator.webkitTemporaryStorage

지금까지 브라우저는 매우 오래되고 지원 중단된 window.webkitStorageInfo, 아직은 비표준이지만 여전히 비표준 navigator.webkitTemporaryStorage처럼 접두사가 붙은 인터페이스를 통해 이러한 유형의 검사를 지원했습니다. 이러한 인터페이스는 유용한 정보를 제공하지만 향후 웹 표준으로 사용할 수는 없습니다.

이러한 경우에 WhatWG Storage Standard가 필요합니다.

미래: navigator.storage

Storage Living Standard 관련 지속적인 작업의 일환으로 몇 가지 유용한 API가 브라우저에 navigator.storage로 노출되는 StorageManager 인터페이스에 추가되었습니다. 다른 여러 최신 웹 API와 마찬가지로 navigator.storage는 HTTPS 또는 localhost를 통해 제공되는 보안 출처에서만 사용할 수 있습니다.

지난해 Google에서는 웹 애플리케이션이 자동 정리에서 스토리지를 제외하도록 요청할 수 있는 navigator.storage.persist() 메서드를 도입했습니다.

이제 navigator.webkitTemporaryStorage.queryUsageAndQuota()의 최신 대체 기능인 navigator.storage.estimate() 메서드에 의해 결합됩니다. estimate()는 비슷한 정보를 반환하지만 다른 최신 비동기 API와 유지되는 프로미스 기반 인터페이스를 노출합니다. estimate()가 반환하는 프로미스는 두 가지 속성, 즉 현재 사용되는 바이트 수를 나타내는 usage와 현재 출처가 저장할 수 있는 최대 바이트를 나타내는 quota가 포함된 객체로 결정됩니다. (스토리지와 관련된 다른 모든 항목과 마찬가지로 할당량은 전체 출처에 적용됩니다.)

웹 애플리케이션이 IndexedDB 또는 Cache Storage API 등을 사용하여 사용 가능한 할당량을 통해 주어진 출처를 가져올 만큼 충분히 큰 데이터를 저장하려고 하면 QuotaExceededError 예외가 발생하고 요청이 실패합니다.

실제 스토리지 추정치

estimate()를 사용하는 정확한 방법은 앱에서 저장해야 하는 데이터 유형에 따라 다릅니다. 예를 들어, 각 저장 작업이 완료된 후 사용 중인 공간을 사용자가 알 수 있도록 인터페이스의 컨트롤을 업데이트할 수 있습니다. 그런 다음 사용자가 더 이상 필요하지 않은 데이터를 수동으로 정리할 수 있는 인터페이스를 제공하는 것이 이상적입니다. 다음 행을 따라 코드를 작성할 수 있습니다.

// For a primer on async/await, see
// https://developers.google.com/web/fundamentals/getting-started/primers/async-functions
async function storeDataAndUpdateUI(dataUrl) {
  // Pro-tip: The Cache Storage API is available outside of service workers!
  // See https://googlechrome.github.io/samples/service-worker/window-caches/
  const cache = await caches.open('data-cache');
  await cache.add(dataUrl);

  if ('storage' in navigator && 'estimate' in navigator.storage) {
    const {usage, quota} = await navigator.storage.estimate();
    const percentUsed = Math.round(usage / quota * 100);
    const usageInMib = Math.round(usage / (1024 * 1024));
    const quotaInMib = Math.round(quota / (1024 * 1024));

    const details = `${usageInMib} out of ${quotaInMib} MiB used (${percentUsed}%)`;

    // This assumes there's a <span id="storageEstimate"> or similar on the page.
    document.querySelector('#storageEstimate').innerText = details;
  }
}

추정치는 얼마나 정확한가요?

함수에서 다시 가져오는 데이터가 출처가 사용하는 공간의 추정치라는 사실을 놓쳐서는 안 됩니다. 이는 함수 이름 바로 위에 있습니다. usagequota 값 모두 안정적이 아니므로 다음을 고려하는 것이 좋습니다.

  • usage는 지정된 출처에서 동일 출처 데이터에 효과적으로 사용하는 바이트 수를 나타내며, 이는 결과적으로 내부 압축 기술, 미사용 공간이 포함될 수 있는 고정 크기 할당 블록, 삭제 후에 일시적으로 생성될 수 있는 'Tombstone' 레코드의 존재에 영향을 받을 수 있습니다. 정확한 크기 정보의 유출을 방지하기 위해 로컬에 저장된 교차 출처 불투명 리소스는 전체 usage 값에 추가 패딩 바이트를 기여할 수 있습니다.
  • quota는 출처에 현재 예약된 공간을 나타냅니다. 이 값은 전체 저장소 크기와 같은 일부 상수 요소뿐만 아니라 현재 사용되지 않는 저장공간의 크기를 비롯한 여러 가지 휘발성 요인에 따라 달라집니다. 따라서 기기의 다른 애플리케이션이 데이터를 쓰거나 삭제함에 따라 브라우저에서 웹 앱의 출처에 할애하는 공간의 양이 변경될 가능성이 높습니다.

현재: 특성 감지 및 대체

estimate()는 Chrome 61부터 기본적으로 사용 설정됩니다. Firefox는 navigator.storage로 실험 중이지만 2017년 8월 기준으로 기본적으로 사용 설정되어 있지 않습니다. 테스트하려면 dom.storageManager.enabled 환경설정을 사용 설정해야 합니다.

아직 모든 브라우저에서 지원되지 않는 기능을 사용하는 경우 특성 감지는 필수입니다. 이전 navigator.webkitTemporaryStorage 메서드 외에 기능 감지와 프로미스 기반 래퍼를 결합하여 다음 줄을 따라 일관된 인터페이스를 제공할 수 있습니다.

function storageEstimateWrapper() {
  if ('storage' in navigator && 'estimate' in navigator.storage) {
    // We've got the real thing! Return its response.
    return navigator.storage.estimate();
  }

  if ('webkitTemporaryStorage' in navigator &&
      'queryUsageAndQuota' in navigator.webkitTemporaryStorage) {
    // Return a promise-based wrapper that will follow the expected interface.
    return new Promise(function(resolve, reject) {
      navigator.webkitTemporaryStorage.queryUsageAndQuota(
        function(usage, quota) {resolve({usage: usage, quota: quota})},
        reject
      );
    });
  }

  // If we can't estimate the values, return a Promise that resolves with NaN.
  return Promise.resolve({usage: NaN, quota: NaN});
}