נתונים שזמינים במצב אופליין

כדי ליצור חוויית שימוש יציבה אופליין, צריך לנהל את האחסון ל-PWA. בפרק בנושא שמירה במטמון למדתם שאחסון במטמון הוא אחת מהאפשרויות לשמירת נתונים במכשיר. בפרק הזה נסביר איך לנהל נתונים ממקורות אופליין, כולל התחזקות הנתונים, המגבלות והכלים הזמינים.

אחסון

נפח האחסון הוא לא רק קבצים ונכסים, אלא יכול לכלול סוגים אחרים של נתונים. בכל הדפדפנים שתומכים באפליקציות PWA, ממשקי ה-API הבאים זמינים לאחסון במכשיר:

  • IndexedDB: אפשרות אחסון של אובייקטים ב-NoSQL לנתונים מובְנים ול-blobs (נתונים בינאריים).
  • WebStorage: דרך לאחסן צמדי מפתח/ערך באמצעות אחסון מקומי או אחסון סשן. היא לא זמינה בהקשר של קובץ שירות (service worker). ה-API הזה סינכרוני ולכן לא מומלץ באחסון נתונים מורכבים.
  • אחסון במטמון: כפי שמתואר במודול השמירה במטמון.

אפשר לנהל את כל האחסון במכשיר באמצעות Storage Manager API בפלטפורמות נתמכות. ה-cache Storage API ו-IndexedDB מספקים גישה אסינכרונית לאחסון מתמיד של אפליקציות PWA וניתן לגשת אליהם מה-thread הראשי, מ-Web worker ומ-Service Workers. לשניהם יש תפקיד חשוב בשיפור הביצועים של אפליקציות PWA כשהרשת לא יציבה או לא קיימת. אבל מתי כדאי להשתמש בכל אחת מהן?

השתמש ב-Cache Storage API למשאבי רשת, דברים שכדי לגשת אליהם באמצעות כתובת אתר כמו HTML, CSS, JavaScript, תמונות, סרטונים ואודיו.

כדי לאחסן נתונים מובְנים, צריך להשתמש ב-IndexedDB. נכללים בכך נתונים שצריכים להיות ניתנים לחיפוש או לשילוב בסגנון NoSQL, וגם נתונים אחרים כמו נתונים ספציפיים למשתמש שלא בהכרח תואמים לבקשה של כתובת URL. חשוב לשים לב ש-IndexedDB לא מיועד לחיפוש טקסט מלא.

IndexedDB

כדי להשתמש ב-IndexedDB, קודם צריך לפתוח מסד נתונים. פעולה זו יוצרת מסד נתונים חדש אם לא קיים מסד נתונים כזה. IndexedDB הוא API אסינכרוני, אבל הוא מבצע קריאה חוזרת במקום להחזיר Promise. בדוגמה הבאה נשתמש בספריית idb של ג'ייק ארצ'יבלד, שהיא wrapper קטן של Promise עבור IndexedDB. אין צורך בספריות מסייעות כדי להשתמש ב-IndexedDB, אבל אם רוצים להשתמש בתחביר Promise אפשר להשתמש בספרייה idb.

הדוגמה הבאה יוצרת מסד נתונים לאחסון מתכונים לבישול.

יצירה ופתיחה של מסד נתונים

כדי לפתוח מסד נתונים:

  1. יש להשתמש בפונקציה openDB כדי ליצור מסד נתונים חדש מסוג IndexedDB בשם cookbook. מכיוון שלמסדי הנתונים IndexedDB יש גרסאות, עליך להגדיל את מספר הגרסה בכל פעם שמבצעים שינויים במבנה מסד הנתונים. הפרמטר השני הוא גרסת מסד הנתונים. בדוגמה הזו מוגדר ל-1.
  2. אובייקט אתחול שמכיל קריאה חוזרת (callback) של 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 או ב-Web Inspector ב-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;
}

לאחר הוספת קובצי ה-Cookie, המתכון יופיע במסד הנתונים עם מתכונים אחרים. המזהה מוגדר וגדל באופן אוטומטי ב-IndexDB. אם תריצו את הקוד הזה פעמיים, יהיו לכם שתי רשומות זהות של קובצי Cookie.

הנתונים בתהליך אחזור

כך מקבלים נתונים מ-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 , Web Storage ואפילו קובץ ה-Service 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. אם המשתמש התקין סמל של ה-PWA במערכת ההפעלה, יכול להיות שהדפדפן יקצה אחסון קבוע.

Mozilla Firefox מבקש מהמשתמש הרשאה לשמירה על אחסון תמידית.

תמיכה בדפדפן API

אחסון באינטרנט

תמיכה בדפדפן

  • 4
  • 12
  • 3.5
  • 4

מקור

גישה למערכת קבצים

תמיכה בדפדפן

  • 86
  • 86
  • 111
  • 15.2

מקור

מנהל אחסון

תמיכה בדפדפן

  • 55
  • 79
  • 57
  • 15.2

מקור

משאבים