사용 가능한 저장공간 예측

tl;dr

더 많은 브라우저가 출시될 예정이므로 이제 다음을 통해 웹 앱에서 사용 중인 저장용량과 사용 가능한 저장용량의 추정치가 표시됩니다.

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 표준에 관한 진행 중인 작업의 일환으로 몇 가지 유용한 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;
  }
}

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

함수에서 다시 가져오는 데이터는 출처가 사용 중인 공간의 추정치일 뿐이라는 사실을 놓칠 수는 없습니다. 바로 함수 이름에 있습니다. usage 또는 quota 값은 안정적일 수 없으므로 다음 사항을 고려하는 것이 좋습니다.

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

현재: 특성 감지 및 대체

Chrome 61부터 estimate()가 기본적으로 사용 설정됩니다. 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});
}