אירועי דחיפה

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

אירוע ה-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.');
    }
});

החלק המוזר ביותר בקוד הזה לרוב המפתחים שלא מכירים את ה-service worker הוא המשתנה 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 Worker הוא שיש לכם מעט שליטה על המועד שבו הקוד של ה-Service Worker ירוץ. הדפדפן מחליט מתי להעיר אותו ומתי לסיים אותו. הדרך היחידה לומר לדפדפן "היי, אני עסוק מאוד בדברים חשובים" היא להעביר הבטחה (promise) לשיטה event.waitUntil(). כך הדפדפן ימשיך לפעול עד שההבטחה שהעברתם תפוג.

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

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

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

    event.waitUntil(promiseChain);
});

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

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

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

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().

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

לאן ממשיכים

Codelabs