การประมาณพื้นที่เก็บข้อมูลที่ใช้ได้

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.`);
  });
}

เว็บแอปและพื้นที่เก็บข้อมูลที่ทันสมัย

เมื่อนึกถึงความต้องการด้านพื้นที่เก็บข้อมูลของเว็บแอปพลิเคชันสมัยใหม่ การจำแนกข้อมูลที่จัดเก็บไว้เป็น 2 หมวดหมู่ ได้แก่ ข้อมูลหลักที่จำเป็นในการโหลดเว็บแอปพลิเคชัน และข้อมูลที่จำเป็นต่อการสร้างการโต้ตอบที่มีความหมายของผู้ใช้เมื่อโหลดแอปพลิเคชันแล้ว

ข้อมูลประเภทแรกซึ่งจำเป็นสำหรับการโหลดเว็บแอปประกอบด้วย HTML, JavaScript, CSS และอาจมีรูปภาพบางส่วน โปรแกรมทำงานของบริการ ตลอดจน Cache Storage API มีโครงสร้างพื้นฐานที่จำเป็นสำหรับการบันทึกทรัพยากรหลักเหล่านั้น แล้วใช้ทรัพยากรเหล่านั้นในภายหลังเพื่อโหลดเว็บแอปอย่างรวดเร็ว ซึ่งจะดีที่สุดโดยข้ามเครือข่ายทั้งหมด (เครื่องมือที่ผสานรวมกับกระบวนการบิลด์ของเว็บแอป เช่น ไลบรารี Workbox ใหม่หรือไลบรารี sw-precache รุ่นเก่า จะทำให้กระบวนการจัดเก็บ อัปเดต และใช้ข้อมูลประเภทนี้เป็นแบบอัตโนมัติได้)

แล้วข้อมูลประเภทอื่นล่ะ ทรัพยากรเหล่านี้เป็นทรัพยากรที่ไม่จำเป็นในการโหลดเว็บแอป แต่อาจมีบทบาทสำคัญในประสบการณ์โดยรวมของผู้ใช้ ตัวอย่างเช่น หากคุณกำลังเขียนเว็บแอปสำหรับแก้ไขรูปภาพ คุณอาจต้องการบันทึกสำเนารูปภาพหนึ่งหรือหลายสำเนาไว้ในเครื่องเพื่อให้ผู้ใช้สลับระหว่างการแก้ไขและเลิกทำการแก้ไขได้ หรือหากคุณกำลังพัฒนาประสบการณ์การเล่นสื่อแบบออฟไลน์ การบันทึกไฟล์เสียงหรือวิดีโอไว้ในเครื่องจะเป็นฟีเจอร์สำคัญ เว็บแอปทุกรายการที่สามารถปรับเปลี่ยนในแบบของคุณได้จะต้องบันทึกข้อมูลสถานะบางอย่าง คุณจะทราบได้อย่างไรว่าพื้นที่เก็บข้อมูลรันไทม์ประเภทนี้มีพื้นที่ว่างเท่าใด และจะเกิดอะไรขึ้นเมื่อพื้นที่เก็บข้อมูลเต็ม

อดีต: window.webkitStorageInfo และ navigator.webkitTemporaryStorage

ที่ผ่านมา เบราว์เซอร์รองรับการสำรวจความคิดเห็นประเภทนี้ผ่านทางอินเทอร์เฟซ นำหน้า เช่น เวอร์ชันเก่ามาก (และเลิกใช้งานแล้ว) window.webkitStorageInfo และอาจไม่เก่ามากแต่ยังคงไม่เป็นไปตามมาตรฐาน navigator.webkitTemporaryStorage แม้ว่าอินเทอร์เฟซเหล่านี้จะให้ข้อมูลที่เป็นประโยชน์ แต่ก็ไม่มีอนาคตเป็นมาตรฐานเว็บ

ซึ่งเป็นจุดที่ WHATWG Storage Standard ใส่รูปภาพ

อนาคต: navigator.storage

เราได้พัฒนา API ที่เป็นประโยชน์ 2 รายการบนอินเทอร์เฟซ StorageManager ซึ่งแสดงในเบราว์เซอร์ต่างๆ เป็น navigator.storage ซึ่งเป็นส่วนหนึ่งของการพัฒนา Storage Living Standard อย่างต่อเนื่อง navigator.storage มีให้ใช้งานเฉพาะในต้นทางที่ปลอดภัย (แสดงผลผ่าน HTTPS หรือ localhost) เท่านั้น เช่นเดียวกับ API ของเว็บรุ่นใหม่อื่นๆ อีกมากมาย

เมื่อปีที่แล้ว เราได้เปิดตัวเมธอด navigator.storage.persist() ซึ่งช่วยให้เว็บแอปพลิเคชันขอยกเว้นพื้นที่เก็บข้อมูลจากการทำความสะอาดอัตโนมัติ

ขณะนี้มีการนำมารวมกันโดยใช้เมธอด navigator.storage.estimate() ซึ่งทำหน้าที่แทน navigator.webkitTemporaryStorage.queryUsageAndQuota() ที่ทันสมัย estimate() แสดงผลข้อมูลที่คล้ายกัน แต่จะแสดงอินเทอร์เฟซที่อิงตามสัญญา ซึ่งสอดคล้องกับ API อะซิงโครนัสสมัยใหม่อื่นๆ สัญญาที่ estimate() จะแสดงผลจะมีการแก้ไขด้วยออบเจ็กต์ที่มีพร็อพเพอร์ตี้ 2 รายการ ได้แก่ 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" ที่อาจสร้างขึ้นชั่วคราวหลังจากการลบ เพื่อป้องกันไม่ให้ข้อมูลขนาดที่แน่นอนรั่วไหล ทรัพยากรที่คลุมเครือแบบข้ามต้นทางและบันทึกไว้ในเครื่องอาจมีไบต์ Padding เพิ่มเติมให้กับค่า usage โดยรวม
  • quota แสดงปริมาณพื้นที่ซึ่งสำรองไว้สำหรับต้นทางในขณะนี้ ค่านี้ขึ้นอยู่กับปัจจัยคงที่บางอย่าง เช่น ขนาดพื้นที่เก็บข้อมูลโดยรวม แต่ปัจจัยที่อาจผันผวนอีกหลายอย่าง เช่น จำนวนพื้นที่เก็บข้อมูลที่ยังไม่ได้ใช้ในปัจจุบัน เช่นเดียวกับที่แอปพลิเคชันอื่นๆ ในอุปกรณ์เขียนหรือลบข้อมูล จำนวนพื้นที่ที่เบราว์เซอร์ยินดีแบ่งให้กับต้นทางของเว็บแอปก็มักจะเปลี่ยนแปลง

ปัจจุบัน: การตรวจหาฟีเจอร์และฟีเจอร์สำรอง

ระบบจะเปิดใช้ estimate() โดยค่าเริ่มต้นใน Chrome 61 เป็นต้นไป Firefox กำลังทดสอบกับ navigator.storage แต่ตั้งแต่เดือนสิงหาคม 2017 เป็นต้นไป ฟีเจอร์ดังกล่าวไม่ได้เปิดใช้งานโดยค่าเริ่มต้น คุณต้องเปิดใช้ค่ากำหนด dom.storageManager.enabled เพื่อทดสอบ

เมื่อทำงานกับฟังก์ชันการทำงานที่ยังไม่รองรับในเบราว์เซอร์ทั้งหมด การตรวจหาฟีเจอร์เป็นสิ่งที่จำเป็น คุณรวมการตรวจหาฟีเจอร์เข้ากับ Wrapper ที่อิงตามสัญญาได้นอกเหนือจากเมธอด 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});
}