מדריך ציווי לשמירה במטמון

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

ייתכן שחלק מהאתרים יצטרכו לתקשר עם Service Worker ללא צורך לגבי התוצאה. הנה כמה דוגמאות:

  • דף שולח ל-Service Worker רשימה של כתובות URL שליפה מראש (prefetch), כך שכאשר המשתמש ילחץ על לקשר את משאבי המשנה של המסמך או הדף כבר זמינים במטמון, וכתוצאה מכך לניווט מהיר יותר.
  • הדף מבקש מה-Service Worker לאחזר ולשמור קבוצה של מאמרים מובילים במטמון לשימוש במצב אופליין.

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

תרשים דף שמבקש משאבים במטמון של קובץ שירות (service worker).

במדריך הזה נראה איך להטמיע טכניקת תקשורת חד-כיוונית מהדף את Service Worker באמצעות ממשקי API רגילים של הדפדפן וספריית Workbox. אפשר לקרוא לסוגים האלה חשוב לשמור במטמון.

סביבת ייצור

1-800-Flowers.com הטמיע שמירה במטמון חיוני (אחזור מראש) עם Service Workers דרך postMessage() כדי לאחזר מראש את הפריטים המובילים בדפי קטגוריות כדי לזרז את הניווט אל דפים של פרטי מוצרים.

לוגו של 1-800 Flowers.

הם משתמשים בגישה משולבת כדי להחליט אילו פריטים לשליפה מראש:

  • בזמן טעינת הדף, הוא מבקש מה-service worker לאחזר את נתוני ה-JSON של 9 הפריטים המובילים. להוסיף למטמון את האובייקטים של התגובה שנוצרו.
  • לגבי הפריטים הנותרים, הם מאזינים לmouseover , אז כש המשתמש מעביר את הסמן מעל לפריט, הוא יכול להפעיל אחזור למשאב לפי דרישה.

הם משתמשים ב-Cache API כדי לאחסן JSON תגובות:

לוגו של 1-800 Flowers.
אחזור מראש של נתוני מוצרים בפורמט JSON מדפי כרטיסי מוצר בכתובת 1-800Flowers.com
.

כשמשתמש לוחץ על פריט, אפשר לאסוף מהמטמון את נתוני ה-JSON שמשויכים אליו, בלי צורך לגשת לרשת, וכך הניווט מהיר יותר.

שימוש בתיבת העבודה

תיבת העבודה מספקת דרך קלה לשלוח הודעות אל קובץ שירות (service worker), באמצעות חבילת workbox-window, קבוצת מודולים שמיועדות לפעול בהקשר של החלון. המוצרים האלה משלימים את החבילות האחרות של Workbox שרצים ב-Service Worker.

כדי לתקשר את הדף עם Service Worker, יש לקבל תחילה הפניה לאובייקט Workbox Service Worker רשום:

const wb = new Workbox('/sw.js');
wb.register();

לאחר מכן תוכלו לשלוח את ההודעה באופן ישיר באופן הצהרתי, בלי הטרחה של קבלת ההודעה הרשמה, בדיקת הפעלה או חשיבה על ממשק ה-API הבסיסי לתקשורת:

wb.messageSW({"type": "PREFETCH", "payload": {"urls": ["/data1.json", "data2.json"]}}); });

ה-Service Worker מיישם handler של message כדי להאזין להודעות האלה. הוא יכול גם להחזיר תשובה, אבל במקרים כמו זה, אין צורך:

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PREFETCH') {
    // do something
  }
});

שימוש בממשקי API לדפדפנים

אם ספריית Workbox לא מתאימה לצרכים שלכם, כך אפשר להטמיע חלון בשירות תקשורת בין עובדים באמצעות ממשקי API של דפדפנים.

postMessage API ניתן להשתמש במנגנון תקשורת חד-כיווני מהדף אל קובץ השירות (service worker).

הדף קורא postMessage() ב- ממשק של קובץ שירות (service worker):

navigator.serviceWorker.controller.postMessage({
  type: 'MSG_ID',
  payload: 'some data to perform the task',
});

ה-Service Worker מיישם handler של message כדי להאזין להודעות האלה.

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === MSG_ID) {
    // do something
  }
});

המאפיין {type : 'MSG_ID'} אינו חובה לחלוטין, אבל זו אחת הדרכים לאפשר לדף לשלוח סוגים שונים של הוראות ל-Service Worker (כלומר, 'שליפה מראש' לעומת 'ניקוי' '). קובץ השירות (service worker) יכול להסתעף לנתיבי הפעלה שונים על סמך הדגל הזה.

אם הפעולה בוצעה בהצלחה, המשתמש יוכל ליהנות מהיתרונות שלה, אבל אם לא, היא לא תשנה את התהליך הראשי של המשתמש. לדוגמה, כש- 1-800-Flowers.com מנסה לשמור מראש במטמון, הדף לא צריך לדעת אם ה-Service Worker הצליח. אם כן, המשתמש ייהנה מניווט מהיר יותר. אם הוא לא צריך עדיין לנווט לדף החדש. זה ייקח עוד קצת זמן.

דוגמה פשוטה לשליפה מראש (prefetch)

אחת האפליקציות הנפוצות ביותר של שמירה במטמון היא שליפה מראש (prefetch), כלומר אחזור לכתובת אתר נתונה, לפני שהמשתמש עובר אליה, כדי לזרז את הניווט.

יש דרכים שונות להטמעת שליפה מראש באתרים:

בתרחישים פשוטים יחסית של שליפה מראש, כמו שליפה מראש של מסמכים או נכסים ספציפיים (JS, שירות CSS וכו'), השיטות האלה הן הגישה הטובה ביותר.

אם נדרשת לוגיקה נוספת, למשל ניתוח משאב השליפה מראש (prefetch) (קובץ או דף JSON) ב- לאחזור כתובות ה-URL הפנימיות שלו, עדיף להאציל את המשימה הזאת לגמרי Service Worker.

אלה היתרונות של האצלת פעולות מהסוגים האלה ל-Service Worker:

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

אחזור מראש של דפים של פרטי מוצרים

השימוש הראשון ב-postMessage() מופעל ממשק של קובץ שירות (service worker) ומעביר מערך של כתובות URL למטמון:

navigator.serviceWorker.controller.postMessage({
  type: 'PREFETCH',
  payload: {
    urls: [
      'www.exmaple.com/apis/data_1.json',
      'www.exmaple.com/apis/data_2.json',
    ],
  },
});

ב-Service Worker, מטמיעים handler של message כדי מיירטים ומעבדים הודעות שנשלחות על ידי כרטיסייה פעילה כלשהי:

addEventListener('message', (event) => {
  let data = event.data;
  if (data && data.type === 'PREFETCH') {
    let urls = data.payload.urls;
    for (let i in urls) {
      fetchAsync(urls[i]);
    }
  }
});

בקוד הקודם הצגנו פונקציית עזר קטנה בשם fetchAsync() כדי לבצע איטרציה מערך של כתובות URL ושולחים בקשת אחזור לכל אחת מהן:

async function fetchAsync(url) {
  // await response of fetch call
  let prefetched = await fetch(url);
  // (optionally) cache resources in the service worker storage
}

כשמתקבלת תגובה, אפשר להסתמך על כותרות השמירה של המשאב במטמון. במקרים רבים אבל, כמו בדפים של פרטי מוצרים, משאבים לא נשמרים במטמון (כלומר, כותרת Cache-control של no-cache). במקרים כאלה ניתן לבטל את ההתנהגות הזו, על ידי אחסון המשאב שאוחזר במטמון של Service Worker. יש להם יתרון נוסף: שיוצג בתרחישים אופליין.

מעבר לנתוני JSON

אחרי שנתוני ה-JSON נשלפים מנקודת קצה של השרת, לרוב הם מכילים כתובות URL אחרות שכדאי לאחזר מראש, כמו תמונה או נתונים אחרים של נקודת הקצה שמשויכים לרמה הראשונה .

נניח שבדוגמה שלנו, נתוני ה-JSON שמוחזרים הם המידע של אתר קניות של מצרכים:

{
  "productName": "banana",
  "productPic": "https://cdn.example.com/product_images/banana.jpeg",
  "unitPrice": "1.99"
 }

משנים את הקוד fetchAsync() כדי לחזור על רשימת המוצרים ולשמור במטמון את התמונה הראשית (Hero) כל אחד מהם:

async function fetchAsync(url, postProcess) {
  // await response of fetch call
  let prefetched = await fetch(url);

  //(optionally) cache resource in the service worker cache

  // carry out the post fetch process if supplied
  if (postProcess) {
    await postProcess(prefetched);
  }
}

async function postProcess(prefetched) {
  let productJson = await prefetched.json();
  if (productJson && productJson.product_pic) {
    fetchAsync(productJson.product_pic);
  }
}

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

סיכום

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

אתם יכולים למצוא דפוסים נוספים של תקשורת דפים ו-Service Worker במקומות הבאים:

  • עדכוני שידור: התקשרות לדף מ-Service Worker כדי ליידע את המשתמשים על עדכונים חשובים (למשל, יש גרסה חדשה של אפליקציית האינטרנט).
  • תקשורת דו-כיוונית: האצלת משימה לעובדי שירות (למשל, הורדה משמעותית), ולדאוג לעדכן את הדף לגבי ההתקדמות.