البيانات بلا اتصال بالإنترنت

للحصول على تجربة قوية بلا اتصال بالإنترنت، يحتاج تطبيق الويب التقدّمي (PWA) إلى إدارة مساحة التخزين. تعلّمت في فصل التخزين المؤقت أن سعة تخزين ذاكرة التخزين المؤقت هي أحد خيارات حفظ البيانات على الجهاز. في هذا الفصل، سنوضِّح لك كيفية إدارة البيانات بلا اتصال بالإنترنت، بما في ذلك ثبات البيانات والقيود واستخدام الأدوات المتاحة.

مساحة التخزين

لا يقتصر التخزين على الملفات والأصول فحسب، بل يمكن أن يتضمّن أنواعًا أخرى من البيانات. في جميع المتصفّحات التي تتوافق مع تطبيقات الويب التقدّمية (PWA)، تتوفّر واجهات برمجة التطبيقات التالية للتخزين على الجهاز:

  • IndexedDB: خيار تخزين كائن NoSQL للبيانات المنظَّمة والكائنات الثنائية الكبيرة (blob) (البيانات الثنائية).
  • WebStorage: طريقة لتخزين أزواج مفاتيح/قيم القيمة باستخدام مساحة تخزين محلية أو تخزين جلسة وهي غير متوفّرة في سياق مشغّل الخدمات. واجهة برمجة التطبيقات هذه متزامنة، لذا لا يُنصح باستخدامها لتخزين البيانات المعقّدة.
  • مساحة تخزين ذاكرة التخزين المؤقت: كما هو موضّح في وحدة التخزين المؤقت.

يمكنك إدارة مساحة التخزين على الجهاز بالكامل باستخدام واجهة برمجة تطبيقات "إدارة مساحة التخزين" على الأنظمة الأساسية المتوافقة. توفِّر واجهة برمجة التطبيقات Cache Storage API وIndexedDB إمكانية الوصول غير المتزامن إلى مساحة تخزين دائمة لتطبيقات الويب التقدّمية (PWA) ويمكن الوصول إليها من سلسلة المحادثات الرئيسية وعاملي الويب وعاملي الخدمات. يلعب كلاهما أدوارًا أساسية في جعل تطبيقات الويب التقدّمية (PWA) تعمل بشكل موثوق عندما تكون الشبكة غير مستقرة أو غير موجودة. ولكن متى يجب استخدام كلٍّ منها؟

استخدِم cache Storage API لموارد الشبكة التي يمكنك الوصول إليها عن طريق طلبها عبر عنوان URL، مثل HTML وCSS وJavaScript والصور والفيديوهات والصوت.

استخدِم IndexedDB لتخزين البيانات المنظَّمة. يتضمن ذلك البيانات التي يجب أن تكون قابلة للبحث أو قابلة للدمج بطريقة تشبه NoSQL، أو بيانات أخرى مثل البيانات الخاصة بالمستخدم التي لا تتطابق بالضرورة مع طلب عنوان URL. يُرجى العِلم أنّ أداة IndexedDB غير مصمّمة للبحث في النص الكامل.

IndexedDB

لاستخدام IndexedDB، افتح قاعدة بيانات أولاً. يؤدي ذلك إلى إنشاء قاعدة بيانات جديدة إذا لم تكن هناك قاعدة بيانات. واجهة برمجة التطبيقات IndexedDB هي واجهة برمجة تطبيقات غير متزامنة، إلا أنها تتطلب معاودة الاتصال بدلاً من عرض وعد. يستخدم المثال التالي مكتبة idb لجيك أرشيبالد، وهي برنامج تضمين صغير من نوع Promise لقاعدة البيانات المفهرسة. المكتبات المساعدة غير مطلوبة لاستخدام IndexedDB، ولكن إذا كنت تريد استخدام بنية Promise، تكون مكتبة idb متاحة.

يقوم المثال التالي بإنشاء قاعدة بيانات لحفظ وصفات الطهي.

إنشاء قاعدة بيانات وفتحها

لفتح قاعدة بيانات:

  1. استخدِم الدالة openDB لإنشاء قاعدة بيانات IndexedDB جديدة تُسمى cookbook. نظرًا لأن قواعد بيانات IndexedDB ذات إصدارات مختلفة، تحتاج إلى زيادة رقم الإصدار كلما أجريت تغييرات على بنية قاعدة البيانات. المعلمة الثانية هي إصدار قاعدة البيانات. في المثال، يتم تعيينها على 1.
  2. يتم تمرير كائن إعداد يحتوي على معاودة الاتصال upgrade() إلى openDB(). يتم استدعاء دالة الاستدعاء عند تثبيت قاعدة البيانات لأول مرة أو عند ترقيتها إلى إصدار جديد. هذه الدالة هي المكان الوحيد الذي يمكن أن تحدث فيه الإجراءات. قد تتضمن الإجراءات إنشاء مخازن عناصر جديدة (البِنى التي تستخدمها قاعدة البيانات المفهرسة لتنظيم البيانات) أو الفهارس (التي تريد البحث عنها). هذا أيضًا هو المكان الذي يجب أن يحدث فيه نقل البيانات. تحتوي الدالة upgrade() عادةً على عبارة switch بدون عبارات break للسماح بحدوث كل خطوة بالترتيب، بناءً على الإصدار القديم من قاعدة البيانات.
import { openDB } from 'idb';

async function createDB() {
  // Using https://github.com/jakearchibald/idb
  const db = await openDB('cookbook', 1, {
    upgrade(db, oldVersion, newVersion, transaction) {
      // Switch over the oldVersion, *without breaks*, to allow the database to be incrementally upgraded.
    switch(oldVersion) {
     case 0:
       // Placeholder to execute when database is created (oldVersion is 0)
     case 1:
       // Create a store of objects
       const store = db.createObjectStore('recipes', {
         // The `id` property of the object will be the key, and be incremented automatically
           autoIncrement: true,
           keyPath: 'id'
       });
       // Create an index called `name` based on the `type` property of objects in the store
       store.createIndex('type', 'type');
     }
   }
  });
}

في هذا المثال، يتم إنشاء متجر كائنات داخل قاعدة بيانات cookbook باسم recipes، مع ضبط السمة id كمفتاح فهرسة للمتجر، ثم إنشاء فهرس آخر باسم type، استنادًا إلى السمة type.

لنلقِ نظرة على متجر الكائنات الذي تم إنشاؤه للتو. بعد إضافة وصفات طعام إلى مخزن العناصر وفتح "أدوات مطوري البرامج" على المتصفّحات المستندة إلى Chromium أو Web Inspector (أداة فحص الويب) على Safari، من المفترض أن تظهر لك ما يلي:

متصفّح Safari وChrome يعرضان محتوى IndexedDB.

إضافة البيانات

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

  1. ابدأ معاملة مع ضبط mode على readwrite.
  2. احصل على مخزن الكائنات، حيث ستضيف البيانات.
  3. يمكنك الاتصال بالرقم add() وتزويده بالبيانات التي تحفظها. تتلقى الطريقة البيانات في شكل قاموس (كأزواج مفتاح/قيمة) وتضيفها إلى مخزن الكائنات. يجب أن يكون القاموس قابلاً للاستنساخ باستخدام ميزة الاستنساخ المنظم. إذا أردت تعديل كائن حالي، عليك استدعاء طريقة put() بدلاً من ذلك.

تتضمّن المعاملات وعدًا بقيمة done يتمّ حلّه عند اكتمال المعاملة بنجاح أو رفضها مع حدوث خطأ متعلّق بالمعاملة.

تشير مستندات مكتبة IDB إلى أنّه إذا كنت تكتب محتوًى في قاعدة البيانات، تشير السمة tx.done إلى أنّه تم تطبيق كل المهام بنجاح في قاعدة البيانات. ومع ذلك، من المفيد انتظار العمليات الفردية حتى تتمكّن من رؤية أي أخطاء تسبب في تعذُّر المعاملة.

// Using https://github.com/jakearchibald/idb
async function addData() {
  const cookies = {
      name: "Chocolate chips cookies",
      type: "dessert",
        cook_time_minutes: 25
  };
  const tx = await db.transaction('recipes', 'readwrite');
  const store = tx.objectStore('recipes');
  store.add(cookies);
  await tx.done;
}

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

جارٍ استرداد البيانات

إليك كيفية الحصول على البيانات من IndexedDB:

  1. ابدأ معاملة وحدِّد متجر العناصر أو المتاجر، ونوع المعاملة اختياريًا.
  2. يمكنك الاتصال بالرقم objectStore() من تلك المعاملة. تأكَّد من تحديد اسم متجر العناصر.
  3. يمكنك الاتصال بـ "get()" باستخدام المفتاح الذي تريد الحصول عليه. يستخدم المتجر مفتاحه كفهرس بشكل تلقائي.
// Using https://github.com/jakearchibald/idb
async function getData() {
  const tx = await db.transaction('recipes', 'readonly')
  const store = tx.objectStore('recipes');
// Because in our case the `id` is the key, we would
// have to know in advance the value of the id to
// retrieve the record
  const value = await store.get([id]);
}

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

وتُعد معرفة كيفية إدارة مساحة تخزين تطبيق الويب التقدّمي (PWA) مهمة بشكل خاص لتخزين استجابات الشبكة وبثها بشكل صحيح.

وتتم مشاركة سعة التخزين بين كل خيارات التخزين، بما في ذلك مساحة تخزين ذاكرة التخزين المؤقت وIndexedDB وتخزين الويب، وحتى ملف مشغّل الخدمات وتبعياته. ويختلف مقدار مساحة التخزين المتاحة من متصفح إلى آخر. من غير المحتمل أن تنفد المساحة المتوفرة. مواقع الويب يمكنها تخزين وحدات الميغابايت وحتى الجيجابايت من البيانات على بعض المتصفحات. فعلى سبيل المثال، يسمح Chrome للمتصفح باستخدام ما يصل إلى 80% من إجمالي مساحة القرص، ويمكن لأصل فردي استخدام ما يصل إلى 60% من مساحة القرص بالكامل. بالنسبة إلى المتصفّحات التي تتوافق مع واجهة Storage API، يمكنك معرفة حجم مساحة التخزين التي لا تزال متاحة لتطبيقك وحصّته ومدى استخدامه. يستخدم المثال التالي Storage API للحصول على الحصة المقدّرة والاستخدام، ثم يحتسب النسبة المئوية المستخدمة ووحدات البايت المتبقية. لاحظ أن navigator.storage تعرض مثيل StorageManager. هناك واجهة Storage منفصلة يسهل الخلط بينها.

if (navigator.storage && navigator.storage.estimate) {
  const quota = await navigator.storage.estimate();
  // quota.usage -> Number of bytes used.
  // quota.quota -> Maximum number of bytes available.
  const percentageUsed = (quota.usage / quota.quota) * 100;
  console.log(`You've used ${percentageUsed}% of the available storage.`);
  const remaining = quota.quota - quota.usage;
  console.log(`You can write up to ${remaining} more bytes.`);
}

في "أدوات مطوري البرامج في Chromium"، يمكنك الاطّلاع على حصة موقعك الإلكتروني ومقدار مساحة التخزين المستخدمة مقسَّمة حسب الاستخدام الذي يستخدمه، وذلك من خلال فتح قسم مساحة التخزين في علامة التبويب التطبيق.

أدوات مطوري البرامج في Chrome في التطبيق، قسم "محو مساحة التخزين"

لا يعرض متصفّحا Firefox وSafari شاشة ملخّص للاطّلاع على كل حصة مساحة التخزين واستخدامها للمصدر الحالي.

الاحتفاظ بالبيانات

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

لطلب سعة تخزين دائمة، اتّصِل بالرقم StorageManager.persist(). كما في السابق، يمكن الوصول إلى الواجهة StorageManager من خلال السمة navigator.storage.

async function persistData() {
  if (navigator.storage && navigator.storage.persist) {
    const result = await navigator.storage.persist();
    console.log(`Data persisted: ${result}`);
}

يمكنك أيضًا التحقّق مما إذا سبق أن تم منح مساحة التخزين الدائمة في المصدر الحالي من خلال طلب الرقم StorageManager.persisted(). يطلب Firefox إذنًا من المستخدم لاستخدام مساحة تخزين دائمة. تمنح المتصفّحات المستندة إلى Chromium الثبات أو ترفضه استنادًا إلى إرشادات لتحديد مدى أهمية المحتوى للمستخدم. ومن معايير Google Chrome، على سبيل المثال، تثبيت تطبيق الويب التقدّمي (PWA). إذا ثبَّت المستخدم رمزًا لتطبيق الويب التقدّمي (PWA) على نظام التشغيل، قد يمنح المتصفّح مساحة تخزين دائمة.

موزيلا فايرفوكس يطلب من المستخدم إذن الاستمرار في التخزين.

دعم واجهة برمجة التطبيقات (API)

تخزين على الويب

دعم المتصفح

  • Chrome: 4-
  • الحافة: 12.
  • Firefox: 3.5
  • Safari: الإصدار 4-

المصدر

الوصول إلى نظام الملفات

دعم المتصفح

  • الإصدار 86 من متصفّح Chrome
  • الحافة: 86.
  • Firefox: 111.
  • Safari: الإصدار 15.2.

المصدر

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

دعم المتصفح

  • Chrome: 55.
  • الحافة: 79.
  • Firefox: 57.
  • Safari: الإصدار 15.2.

المصدر

الموارد