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

เจฟฟ์ พอสนิก
เจฟฟ์ พอสนิก

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 และอาจรวมถึงรูปภาพบางส่วน Service Worker พร้อมด้วย Cache Storage API มอบโครงสร้างพื้นฐานที่จำเป็นสำหรับการบันทึกทรัพยากรหลักเหล่านั้น แล้วนำไปใช้ในภายหลังเพื่อให้โหลดเว็บแอปได้อย่างรวดเร็ว ซึ่งเป็นการข้ามเครือข่ายไปอย่างสิ้นเชิง (เครื่องมือที่ผสานรวมกับกระบวนการบิลด์ของเว็บแอป เช่น ไลบรารี Workbox แบบใหม่หรือ sw-precache เวอร์ชันเก่าจะทำให้กระบวนการจัดเก็บ อัปเดต และใช้ข้อมูลประเภทนี้ได้โดยอัตโนมัติอย่างเต็มรูปแบบ)

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

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

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

ซึ่ง WHATWG Storage Standard จะแสดงภาพนี้

อนาคต: navigator.storage

เพื่อให้สอดคล้องกับ Storage Living Standard อย่างต่อเนื่อง API ที่มีประโยชน์ 2 รายการได้ดำเนินการกับอินเทอร์เฟซ StorageManager ซึ่งเปิดใช้ในเบราว์เซอร์เป็น navigator.storage 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" ซึ่งอาจสร้างขึ้นชั่วคราวหลังจากการลบ ทรัพยากรทึบแสงแบบข้ามต้นทางซึ่งบันทึกไว้ในเครื่องอาจเพิ่มไบต์ระยะห่างจากขอบเพิ่มเติมให้กับค่า 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});
}