사용 가능한 저장공간 예측

요약 정리

앞으로 더 많은 브라우저에서 사용할 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, JavaScript, CSS, 일부 이미지로 구성됩니다. 서비스 워커Cache Storage API와 함께 이러한 핵심 리소스를 저장한 후 나중에 이를 사용하여 웹 앱을 빠르게 로드하는 데 필요한 인프라를 제공합니다(가급적 네트워크를 완전히 우회하는 것이 좋음). 새 Workbox 라이브러리 또는 이전 sw-precache와 같이 웹 앱의 빌드 프로세스와 통합되는 도구는 이러한 유형의 데이터를 저장, 업데이트, 사용하는 프로세스를 완전히 자동화할 수 있습니다.

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

과거: window.webkitStorageInfonavigator.webkitTemporaryStorage

브라우저는 이전부터 매우 오래되고 지원 중단된 window.webkitStorageInfo와 그다지 오래되지 않았지만 여전히 표준이 아닌 navigator.webkitTemporaryStorage과 같은 접두사가 있는 인터페이스를 통해 이러한 유형의 내부 검사를 지원해 왔습니다. 이러한 인터페이스는 유용한 정보를 제공했지만 웹 표준으로서는 미래가 없습니다.

여기서 WHATWG 저장소 표준이 등장합니다.

미래: navigator.storage

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

작년에 웹 애플리케이션이 저장소의 자동 정리를 예외로 요청할 수 있는 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});
}