تقدير مساحة التخزين المتاحة

tl;dr

يعرض الإصدار 61 من Chrome، والذي سيأتي لاحقًا المزيد من المتصفحات، تقديرًا لحجم مساحة التخزين التي يستخدمها تطبيق الويب ومقدار المساحة المتاحة من خلال:

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 وربما بعض الصور. يعمل مشغِّلو الخدمات، جنبًا إلى جنب مع واجهة برمجة تطبيقات تخزين ذاكرة التخزين المؤقت، على توفير البنية الأساسية اللازمة لحفظ هذه الموارد الأساسية ثم استخدامها لاحقًا لتحميل تطبيق الويب بسرعة، وتجاوز الشبكة بالكامل، وبشكل مثالي. (يمكن للأدوات التي تتكامل مع عملية إنشاء تطبيق الويب، مثل مكتبات Workbox الجديدة أو الإصدارات الأقدم sw-precache، أن تعمل تلقائيًا بشكل كامل على عملية تخزين هذا النوع من البيانات وتحديثه واستخدامه).

ولكن ماذا عن النوع الآخر من البيانات؟ هذه موارد غير مطلوبة لتحميل تطبيق الويب الخاص بك، ولكنها قد تلعب دورًا مهمًا في تجربة المستخدم الإجمالية. على سبيل المثال، إذا كنت تكتب تطبيق ويب لتعديل الصور، قد تريد حفظ نسخة محلية أو أكثر من صورة، ما يسمح للمستخدمين بالتبديل بين النُسخ السابقة والتراجع عن عملهم. وإذا كنت تعمل على تطوير تجربة تشغيل الوسائط بلا اتصال بالإنترنت، سيكون حفظ ملفات الصوت أو الفيديو محليًا ميزة مهمة. يحتاج كل تطبيق ويب يمكن تخصيصه إلى حفظ نوع من معلومات الحالة. كيف تعرف حجم المساحة المتوفرة لهذا النوع من سعة التخزين في وقت التشغيل، وماذا يحدث عند نفاد المساحة؟

الماضي: window.webkitStorageInfo وnavigator.webkitTemporaryStorage

في الماضي، اعتمدت المتصفحات هذا النوع من الفحص من خلال واجهات بادئة، مثل الواجهة القديمة جدًا (والمتوقّفة نهائيًا) window.webkitStorageInfo، والواجهات القديمة التي لم تكتمل بعد، ولكنها لا تزال غير عادية، navigator.webkitTemporaryStorage. رغم أن هذه الواجهات قدمت معلومات مفيدة، إلا أنها ليس لها مستقبل كمعايير ويب.

هذا هو المكان الذي يتم فيه إدخال مقياس مساحة التخزين whatWG إلى الصورة.

المستقبل: navigator.storage

في إطار الجهود المتواصلة في إطار العمل على Storage Living Standard، تم دمج واجهات برمجة تطبيقات مفيدة مع واجهة StorageManager التي تظهر للمتصفِّحات باسم navigator.storage. مثل العديد من واجهات برمجة تطبيقات الويب الجديدة الأخرى، لا يتوفّر navigator.storage إلا على مصادر آمنة (يتم عرضها عبر HTTPS أو مضيف محلي).

في العام الماضي، قدَّمنا الطريقة navigator.storage.persist() التي تتيح لتطبيق الويب طلب استثناء مساحة التخزين من عملية التنظيف التلقائي.

تم الانضمام إليها الآن من خلال طريقة navigator.storage.estimate()، والتي تعمل كبديل حديث لـ navigator.webkitTemporaryStorage.queryUsageAndQuota(). ويعرض estimate() معلومات مماثلة، إلا أنّه يعرض واجهة قائمة على الوعد تتوافق مع واجهات برمجة التطبيقات الحديثة غير المتزامنة. الوعد الذي يعرض الدالة estimate() بعنصر يحتوي على سمتَين: usage، الذي يمثّل عدد وحدات البايت المستخدمة حاليًا، وquota، الذي يمثّل الحد الأقصى لوحدات البايت التي يمكن تخزينها من خلال المصدر الحالي. (مثل كل الخدمات الأخرى المتعلقة بمساحة التخزين، يتم تطبيق الحصة على المصدر بالكامل).

إذا حاول أحد تطبيقات الويب تخزين بيانات كبيرة بما يكفي لتجاوز مصدر معيّن للحصّة المتاحة، باستخدام قاعدة بيانات IndexedDB أو واجهة برمجة تطبيقات تخزين ذاكرة التخزين المؤقت، مثلاً، سيتعذّر تنفيذ الطلب باستثناء 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()" تلقائيًا بدءًا من الإصدار 61 من Chrome. يجرّب Firefox navigator.storage، ولكن اعتبارًا من آب (أغسطس) 2017، لن يتم تفعيله تلقائيًا. تحتاج إلى تفعيل تفضيل 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});
}