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

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. على الرغم من أن هذه الواجهات قدمت معلومات مفيدة، ليس لها مستقبل كمعايير ويب.

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

المستقبل: 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() تلقائيًا بدءًا من إصدار Chrome 61. لا يزال 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});
}