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

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

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

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

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

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

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

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

IndexedDB

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

ينشئ المثال التالي قاعدة بيانات لتخزين وصفات الطهي.

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

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

  1. استخدِم الدالة openDB لإنشاء قاعدة بيانات IndexedDB جديدة باسم cookbook. بما أنّ قواعد بيانات IndexedDB لها إصدارات، عليك زيادة رقم الإصدار كلما أجريت تغييرات على بنية قاعدة البيانات. المعلمة الثانية هي إصدار قاعدة البيانات. في المثال، تم ضبطه على 1.
  2. يتم تمرير عنصر إعداد يحتوي على دالة ردّ اتصال upgrade() إلى openDB(). يتمّ استدعاء دالة ردّ الاتصال عند تثبيت قاعدة البيانات لأول مرّة أو عند ترقيتها إلى إصدار جديد. وهذه الدالة هي المكان الوحيد الذي يمكن أن تحدث فيه الإجراءات. قد تشمل الإجراءات إنشاء مستودعات عناصر جديدة (هي البنى التي يستخدمها IndexedDB لتنظيم البيانات) أو الفهارس (التي تريد البحث فيها). وهذا هو المكان الذي من المفترض أن يحدث فيه نقل البيانات أيضًا. تحتوي الدالة 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 أو "أداة فحص الويب" على Safari، من المفترض أن تظهر لك العناصر التالية:

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

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

يستخدم 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. إذا نفّذت هذا الرمز البرمجي مرّتين، سيكون لديك إدخالان متطابقان لملفّ تعريف الارتباط.

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

في ما يلي كيفية الحصول على البيانات من 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 و"تخزين الويب" وحتى ملف worker الخدمة وملفات الاعتماد التابعة له. ومع ذلك، تختلف سعة التخزين المتاحة من متصفّح إلى آخر. من غير المرجّح أن ينفد هذا المساحة، لأنّ المواقع الإلكترونية يمكنها تخزين ميغابايت وحتى غيغابايت من البيانات على بعض المتصفّحات. على سبيل المثال، يسمح متصفّح 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 في نظام التشغيل، قد يمنح المتصفّح مساحة تخزين دائمة.

يطلب متصفّح Mozilla Firefox من المستخدم إذن الاحتفاظ ببيانات التخزين.

توافق واجهة برمجة التطبيقات مع المتصفّح

مساحة التخزين على الويب

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 4.

Source

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

Browser Support

  • Chrome: 86.
  • Edge: 86.
  • Firefox: 111.
  • Safari: 15.2.

Source

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

Browser Support

  • Chrome: 55.
  • Edge: 79.
  • Firefox: 57.
  • Safari: 15.2.

Source

الموارد