אירועי דחיפה

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

אירוע ה-Push

כשמתקבלת הודעה, מתבצעת שליחה של אירוע דחיפה ב-service worker.

הקוד להגדרת listener לאירועי דחיפה אמור להיות דומה למדי לכל listener אחר לאירועים שכותבים ב-JavaScript:

self.addEventListener('push', function(event) {
    if (event.data) {
    console.log('This push event has data: ', event.data.text());
    } else {
    console.log('This push event has no data.');
    }
});

החלק המוזר ביותר בקוד הזה לרוב המפתחים שמתחילים לעבוד עם שירותי העבודה הוא המשתנה self. self משמש בדרך כלל ב-Web Workers, שהם קובצי שירות (service workers). הערך של self מתייחס להיקף הגלובלי, בדומה ל-window בדף אינטרנט. אבל ב-Web Workers וב-Service Workers, הערך של self מתייחס ל-worker עצמו.

בדוגמה שלמעלה, אפשר לחשוב על self.addEventListener() כעל הוספת מאזין לאירועים ל-service worker עצמו.

בדוגמה של אירוע ה-push, אנחנו בודקים אם יש נתונים ומדפיסים משהו במסוף.

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

// Returns string
event.data.text()

// Parses data as JSON string and returns an Object
event.data.json()

// Returns blob of data
event.data.blob()

// Returns an arrayBuffer
event.data.arrayBuffer()

רוב האנשים משתמשים ב-json() או ב-text(), בהתאם לציפיות שלהם מהאפליקציה.

בדוגמה הזו מוסבר איך להוסיף מאזין לאירועי Push ואיך לגשת לנתונים, אבל חסרות בה שתי תכונות חשובות מאוד. לא מוצגת בה התראה והיא לא משתמשת ב-event.waitUntil().

Wait Until

אחד הדברים שחשוב להבין לגבי קובצי שירות (service workers) הוא שיש לכם שליטה מועטה על מועד ההרצה של הקוד של קובץ השירות. הדפדפן מחליט מתי להעיר אותו ומתי לסיים אותו. הדרך היחידה לומר לדפדפן "היי, אני עסוק מאוד בדברים חשובים" היא להעביר הבטחה (promise) לשיטה event.waitUntil(). כך הדפדפן ימשיך להפעיל את קובץ השירות עד שההבטחה שהעברתם תבוצע.

באירועי דחיפה, יש דרישה נוספת להציג התראה לפני שההבטחה שהעברתם תבוצע.

דוגמה בסיסית להצגת התראה:

self.addEventListener('push', function(event) {
    const promiseChain = self.registration.showNotification('Hello, World.');

    event.waitUntil(promiseChain);
});

קריאה ל-self.registration.showNotification() היא השיטה שמציגה התראה למשתמש ומחזירה הבטחה שתתבצע ברגע שההתראה תוצג.

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

דוגמה מורכבת יותר עם בקשת רשת לנתונים ומעקב אחר אירוע הדחיפה באמצעות Analytics עשויה להיראות כך:

self.addEventListener('push', function(event) {
    const analyticsPromise = pushReceivedTracking();
    const pushInfoPromise = fetch('/api/get-more-data')
    .then(function(response) {
        return response.json();
    })
    .then(function(response) {
        const title = response.data.userName + ' says...';
        const message = response.data.message;

        return self.registration.showNotification(title, {
        body: message
        });
    });

    const promiseChain = Promise.all([
    analyticsPromise,
    pushInfoPromise
    ]);

    event.waitUntil(promiseChain);
});

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

כדי לוודא ש-service worker יישאר פעיל בזמן ביצוע שתי המשימות האלה, אפשר לשלב את ההבטחות האלה עם Promise.all(). ההבטחה שמתקבלת מועברת אל event.waitUntil(), כלומר הדפדפן ימתין עד ששתי ההבטחות יסתיימו לפני שהוא יבדוק אם ההתראה הוצגה ויפסיק את ה-service worker.

הסיבה לכך שחשוב להבין את המשמעות של waitUntil() ואת אופן השימוש בו היא שזו אחת מהבעיות הנפוצות ביותר שמפתחים נתקלים בהן: כששרשרת ההבטחה שגויה או שבורה, Chrome מציג את ההתראה 'ברירת המחדל' הבאה:

תמונה של ההתראה שמוגדרת כברירת מחדל ב-Chrome

ההתראה 'האתר הזה עודכן ברקע' תוצג ב-Chrome רק אם מתקבלת הודעת דחיפה ואירוע הדחיפה ב-service worker לא מציג התראה אחרי שההבטחה שהועברה אל event.waitUntil() מסתיימת.

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

self.addEventListener('push', function(event) {
    const analyticsPromise = pushReceivedTracking();
    const pushInfoPromise = fetch('/api/get-more-data')
    .then(function(response) {
        return response.json();
    })
    .then(function(response) {
        const title = response.data.userName + ' says...';
        const message = response.data.message;

        self.registration.showNotification(title, {
        body: message
        });
    });

    const promiseChain = Promise.all([
    analyticsPromise,
    pushInfoPromise
    ]);

    event.waitUntil(promiseChain);
});

קל מאוד לפספס את זה.

חשוב לזכור: אם ההתראה הזו מופיעה, צריך לבדוק את שרשרות ההבטחות וגם את event.waitUntil().

בקטע הבא נסביר מה אפשר לעשות כדי לעצב את ההתראות ואיזה תוכן אפשר להציג.

לאן ממשיכים

Code labs