שדרו את הדרך שלכם לתגובות מיידיות

ג'ף פוזניק
ג'ף פוזניק

כל מי שמשתמש בעובדי שירות יכול לומר לכם שהם אסינכרוניים לגמרי. הם מסתמכים אך ורק על ממשקים מבוססי אירועים, כמו FetchEvent, ומשתמשים בהבטחות כדי לאותת לאחר השלמת פעולות אסינכרוניות.

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

כשכותבים רכיב handler משלכם לאירועים של fetch, נהוג להעביר את השיטה respondWith() Response (או הבטחה ל-Response) באמצעות fetch() או caches.match(), ומתקשרים כל יום. החדשות הטובות הן ש-Response שנוצרו בשתי השיטות האלה כבר ניתנים לסטרימינג! החדשות הרעות הן שאי אפשר לצפות בסטרימינג באופן ידני Response, לפחות עד עכשיו. כאן נכנס לתמונה Streams API.

האזנות?

מקור נתונים הוא מקור נתונים שאפשר ליצור ולבצע בו שינויים באופן מצטבר, והוא מספק ממשק לקריאה או לכתיבה של קטעים אסינכרוניים של נתונים, שרק קבוצת משנה שלהם עשויה להיות זמינה בזיכרון בכל רגע נתון. כרגע אנחנו מתעניינים ב-ReadableStreams, שניתן להשתמש בהם כדי ליצור אובייקט Response שמועבר אל fetchEvent.respondWith():

self.addEventListener('fetch', event => {
    var stream = new ReadableStream({
    start(controller) {
        if (/* there's more data */) {
        controller.enqueue(/* your data here */);
        } else {
        controller.close();
        }
    });
    });

    var response = new Response(stream, {
    headers: {'content-type': /* your content-type here */}
    });

    event.respondWith(response);
});

הדף שהבקשה שלו הקפיצה את האירוע fetch יקבל תגובת סטרימינג מיד לאחר הקריאה ל-event.respondWith(), והקריאה תמשיך מהשידור הזה כל עוד ה-Service Worker ימשיך enqueue()לספק נתונים נוספים. התגובה שזורמת מה-Service Worker לדף היא אסינכרונית לגמרי, ויש לנו שליטה מלאה על מילוי הזרם!

שימושים בעולם האמיתי

בטח שמתם לב שבדוגמה הקודמת היו כמה הערות placeholder מסוג /* your data here */, והפרטים של ההטמעה בפועל לא הוצגו. אז איך תיראה דוגמה מהעולם האמיתי?

לג'ייק ארצ'יבלד (לא מפתיע!) יש דוגמה מצוינת לשימוש בסטרימינג כדי לחבר תגובת HTML מכמה קטעי קוד HTML שנשמרו במטמון, יחד עם נתונים "חיים" שמועברים דרך fetch() - במקרה זה, תוכן עבור הבלוג שלו

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

האזנות? או דוגמאות למעטפת של אפליקציות?

השיטות המומלצות הקיימות בנוגע לשימוש ב-Service Workers כדי להפעיל אפליקציות אינטרנט להתמקד במודל App Shell + תוכן דינמי. כדי להשתמש בשיטה הזו, צריך לשמור במטמון את ה'מעטפת' של אפליקציית האינטרנט – ה-HTML, ה-JavaScript וה-CSS המינימליים שנדרשים כדי להציג את המבנה והפריסה, ואחר כך לטעון את התוכן הדינמי שנדרש לכל דף ספציפי באמצעות בקשה בצד הלקוח.

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

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

אם אתם בשלבי התכנון של ההטמעה של קובץ השירות (service worker), באיזה מודל כדאי לאמץ: תגובות שמופעלות בסטרימינג שעוברות רינדור בהדרגה, או מעטפת פשוטה שמשולבת עם בקשה לתוכן דינמי מצד הלקוח? התשובה היא שלא באופן מפתיע, תלוי אם יש הטמעה קיימת שמתבססת על מערכת ניהול תוכן ועל תבניות חלקיות (יתרון: stream). אם אתם מצפים למטענים ייעודיים (payloads) גדולים ויחידים של HTML, שיהנו מעיבוד מתקדם (יתרון: stream); אם יש לכם אפליקציית האינטרנט המתאימה ביותר בתור אפליקציה בדף יחיד (יתרון: App Shell), או אם יש תמיכה ל-Shells כמה דפדפנים (יתרון: App Shell):

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

בחינה מעמיקה של זרמים

אם אתם יוצרים שידורים קריאים משלכם, יכול להיות שקריאה ל-controller.enqueue() ללא הבחנה עשויה להיות לא מספיקה או יעילה. ג'ייק מסביר בפירוט איך אפשר להשתמש בשיטות start(), pull() ו-cancel() בו-זמנית כדי ליצור מקור נתונים שמותאם לתרחיש לדוגמה שלך.

למי שרוצה פרטים נוספים תוכלו למצוא במפרט של Streams.

תאימות

נוספה תמיכה בבניית אובייקט Response בתוך Service Worker באמצעות ReadableStream כמקור ב-Chrome 52.

הטמעת קובץ השירות (service worker) ב-Firefox עדיין לא תומכת בתשובות שמגובות ב-ReadableStream, אבל קיים באג מעקב רלוונטי בתמיכה ב-Streams API שתוכלו לעקוב אחריו.

בדף סטטוס הפלטפורמה של Microsoft אפשר לעקוב אחרי ההתקדמות בתמיכה ב-Streams API ללא קידומת ב-Edge, לצד תמיכה כוללת ב-Service Worker.