מדידת ההשפעה של אנשי שירות (service worker) על הביצועים בעולם

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

אפליקציית האינטרנט Google I/O (בקיצור IOWA) היא אפליקציית אינטרנט מתקדמת שנעזרת ברוב היכולות החדשות של Service Worker כדי לספק למשתמשים חוויה עשירה דמוית אפליקציה. היא גם השתמשה ב-Google Analytics כדי לתעד נתוני ביצועים מרכזיים ודפוסי שימוש בקרב קהל המשתמשים הגדול והמגוון.

מקרה לדוגמה שבוחן איך IOWA השתמשה ב-Google Analytics כדי לענות על שאלות מפתח בנושא ביצועים ולדווח על ההשפעה של עובדי שירות בעולם האמיתי.

נתחיל עם השאלות

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

רצינו לענות על כמה שאלות, אבל לצורך המקרה לדוגמה הזה נתמקד בשתי שאלות מעניינות יותר.

1. האם שמירה במטמון של Service Worker טובה יותר מאשר המנגנונים הקיימים לשמירה במטמון של HTTP שזמינים בכל הדפדפנים?

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

Service works מציע יכולות חלופיות לשמירה במטמון, שמספקות למפתחים שליטה פרטנית על האופן והאופן שבו השמירה במטמון מתבצעת. ב-IOWA ביצענו אופטימיזציה של הטמעת קובץ השירות (service worker) כך שכל נכס יישמר במטמון, כך שמבקרים חוזרים יוכלו להשתמש באפליקציה במצב אופליין לגמרי.

אבל האם המאמץ הזה יהיה טוב יותר ממה שהדפדפן כבר עושה כברירת מחדל? ואם כן, עד כמה טוב יותר? 1

2. איך קובץ Service Worker משפיע על החוויה של טעינת האתר?

במילים אחרות, באיזו מהירות נוצרת תחושת טעינה של האתר, ללא קשר לזמני הטעינה בפועל שנמדדים לפי המדדים המסורתיים של טעינת דפים?

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

איך לבחור את המדד הנכון

כברירת מחדל, Google Analytics עוקב אחר זמני טעינת דפים (באמצעות Navigation Timing API) עבור 1% מהמבקרים באתר. הנתונים האלה זמינים באמצעות מדדים כמו 'ממוצע זמן הטעינה של דף.

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

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

אחרי שהחלטנו אילו שאלות אנחנו רוצים לענות עליהן וזיהינו את המדדים המועילים לנו לענות עליהן, הגיע הזמן להטמיע את Google Analytics ולהתחיל למדוד.

ההטמעה של ניתוח הנתונים

אם השתמשתם ב-Google Analytics בעבר, סביר להניח שאתם מכירים את קטע הקוד המומלץ למעקב ב-JavaScript. כך הוא נראה:

<script>
window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');
</script>
<script async src="https://www.google-analytics.com/analytics.js"></script>

השורה הראשונה בקוד שלמעלה מפעילה פונקציית ga() גלובלית (אם היא עדיין לא קיימת), והשורה האחרונה מורידה באופן אסינכרוני את הספרייה analytics.js.

החלק האמצעי מכיל את שתי השורות הבאות:

ga('create', 'UA-XXXXX-Y', 'auto');
ga('send', 'pageview');

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

ב-IOWA, רצינו לעקוב אחרי שני דברים נוספים:

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

לכידת הזמן עד לציור הראשון

דפדפנים מסוימים מתעדים את השעה המדויקת שבה נצבע הפיקסל הראשון על המסך, והזמן הזה זמין למפתחים. הערך הזה, בהשוואה לערך navigationStart שנחשף דרך Navigation Timing API, מספק לנו דיווח מדויק מאוד לגבי הזמן שחלף מהמועד שבו המשתמש ביקש את הדף בפעם הראשונה ועד שהוא ראה משהו בפעם הראשונה.

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

כדי לקבל את ערך הצבע הראשון בדפדפנים שחושפים אותו, יצרנו את פונקציית הכלי getTimeToFirstPaintIfSupported:

function getTimeToFirstPaintIfSupported() {
  // Ignores browsers that don't support the Performance Timing API.
  if (window.performance && window.performance.timing) {
    var navTiming = window.performance.timing;
    var navStart = navTiming.navigationStart;
    var fpTime;

    // If chrome, get first paint time from `chrome.loadTimes`.
    if (window.chrome && window.chrome.loadTimes) {
      fpTime = window.chrome.loadTimes().firstPaintTime * 1000;
    }
    // If IE/Edge, use the prefixed `msFirstPaint` property.
    // See http://msdn.microsoft.com/ff974719
    else if (navTiming.msFirstPaint) {
      fpTime = navTiming.msFirstPaint;
    }

    if (fpTime && navStart) {
      return fpTime - navStart;
    }
  }
}

עכשיו אפשר לכתוב פונקציה נוספת ששולחת אירוע ללא אינטראקציה עם הזמן שצריך להציג בתור הערך שלו:3

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    ga('send', 'event', {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    });
  }
}

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

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sends a pageview for the initial pageload.
ga('send', 'pageview');

// Sends an event with the time to first paint data.
sendTimeToFirstPaint();

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

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

הקוד שלמעלה מדווח firstpaint פעמים ל-Google Analytics, אבל זה רק חצי מהסיפור. עדיין היינו צריכים לעקוב אחרי הסטטוס של Service Worker. אחרת, לא נוכל להשוות בין זמני ציור ראשוניים של דף שבשליטתו של קובץ שירות לבין דף לא נשלט.

קביעת הסטטוס של קובץ שירות (service worker)

כדי לקבוע את הסטטוס הנוכחי של Service Worker, יצרנו פונקציית עזר שמחזירה אחד מתוך שלושה ערכים:

  • נשלט: Service Worker שולט בדף. במקרה של IOWA, המשמעות היא שכל הנכסים נשמרו במטמון והדף פועל במצב אופליין.
  • נתמך: הדפדפן תומך ב-Service Worker אבל ה-Service Worker עדיין לא שולט בדף. זהו הסטטוס הצפוי למבקרים חדשים.
  • unsupported: דפדפן המשתמש לא תומך ב-Service Worker.
function getServiceWorkerStatus() {
  if ('serviceWorker' in navigator) {
    return navigator.serviceWorker.controller ? 'controlled' : 'supported';
  } else {
    return 'unsupported';
  }
}

הפונקציה הזו קיבלה את סטטוס Service Worker עבורנו. בשלב הבא, צריך לשייך את הסטטוס הזה לנתונים ששלחנו ל-Google Analytics.

מעקב אחרי נתונים מותאמים אישית באמצעות מאפיינים מותאמים אישית

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

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

עבור IOWA, יצרנו מאפיין מותאם אישית שנקרא סטטוס Worker ומגדירים את ההיקף שלו כ-היט (כלומר, לכל אינטראקציה).4 לכל מאפיין מותאם אישית שיוצרים ב-Google Analytics מקבל אינדקס ייחודי בתוך הנכס הזה, ובקוד המעקב שלכם אפשר להפנות למאפיין הזה לפי האינדקס שלו. לדוגמה, אם האינדקס של המאפיין שיצרנו עכשיו היה 1, נוכל לעדכן את הלוגיקה שלנו כך לשלוח את האירוע firstpaint כך שיכלול את סטטוס קובץ השירות (service worker):

ga('send', 'event', {
  eventCategory: 'Performance',
  eventAction: 'firstpaint',
  // Rounds to the nearest millisecond since
  // event values in Google Analytics must be integers.
  eventValue: Math.round(timeToFirstPaint)
  // Sends this as a non-interaction event,
  // so it doesn't affect bounce rate.
  nonInteraction: true,

  // Sets the current service worker status as the value of
  // `dimension1` for this event.
  dimension1: getServiceWorkerStatus()
});

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

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

ga('set', 'dimension1', getServiceWorkerStatus());

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

הערה קצרה לגבי בהירות הקוד וקריאותו: מאחר שאנשים אחרים שצופים בקוד הזה לא יודעים למה מתייחס dimension1, תמיד מומלץ ליצור משתנה שממפה שמות של מאפיינים משמעותיים לערכים שבהם ישתמש analytics.js.

// Creates a map between custom dimension names and their index.
// This is particularly useful if you define lots of custom dimensions.
var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1'
};

// Creates the tracker object.
ga('create', 'UA-XXXXX-Y', 'auto');

// Sets the service worker status on the tracker,
// so its value is included in all future hits.
ga('set', customDimensions.SERVICE_WORKER_STATUS, getServiceWorkerStatus());

// Postpones sending any hits until after the page has fully loaded.
// This prevents analytics requests from delaying the loading of the page.
window.addEventListener('load', function() {
  // Sends a pageview for the initial pageload.
  ga('send', 'pageview');

  // Sends an event with the time to first paint data.
  sendTimeToFirstPaint();
});

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

כפי שאפשר לראות, כמעט 85% מכל הצפיות בדפים של IOWA הגיעו מדפדפנים שתומכים ב-service worker.

התוצאות: מענה על השאלות שלנו

אחרי שהתחלנו לאסוף נתונים כדי לענות על השאלות שלנו, יכולנו לדווח על הנתונים האלה כדי לראות את התוצאות. (הערה: כל הנתונים של Google Analytics שמוצגים כאן מייצגים את תנועת הגולשים בפועל לאתר IOWA מ-16 עד 22 במאי 2016).

השאלה הראשונה ששאלתי הייתה: האם השמירה במטמון של Service Worker טובה יותר מאשר המנגנונים הקיימים לשמירה במטמון של HTTP שזמינים בכל הדפדפנים?

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

המאפיינים שבחרנו היו:

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

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

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

"...מבקר באפליקציה שלנו כשהוא נשלט על ידי קובץ שירות (service worker) נטען די מהר מביקורים לא מבוקרים..."

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

ממוצע זמן טעינת דף (מחשב)
סטטוס של קובץ שירות (service worker) סוג המשתמש זמן ממוצע של טעינת דף (אלפיות השנייה) גודל הדגימה
שליטה ב: אורח חוזר 2568 30860
נתמך אורח חוזר 3612 1289
נתמך מבקר חדש 4664 21991
ממוצע זמן טעינת דף (בנייד)
סטטוס של קובץ שירות (service worker) סוג המשתמש זמן ממוצע של טעינת דף (אלפיות השנייה) גודל הדגימה
שליטה ב: אורח חוזר 3760 8162
נתמך אורח חוזר 4843 676
נתמך מבקר חדש 6158 5779

ייתכן שתהיתם איך מבקר חוזר שהדפדפן שלו תומך ב-Service Worker יהיה במצב לא מבוקר. יכולים להיות לכך כמה הסברים:

  • המשתמש יצא מהדף בביקור הראשוני לפני של-Service Worker הייתה הזדמנות לסיים את האתחול.
  • המשתמש הסיר את Service Worker באמצעות הכלים למפתחים.

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

השאלה השנייה שלנו הייתה: איך קובץ Service Worker משפיע על החוויה של טעינת האתר?

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

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

"...ל-service worker בנייד הייתה הרבה פחות השפעה על הזמן עד לסימון הראשון, מאשר על הטעינה הכוללת של הדף".

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

הצגת ההתפלגות של מדד ב-Google Analytics

כדי לקבל את ההתפלגות של firstpaint פעמים, אנחנו צריכים גישה לתוצאות הנפרדות של כל אירוע. לצערנו, Google Analytics לא הופך את זה לפשוט.

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

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

var customDimensions = {
  SERVICE_WORKER_STATUS: 'dimension1',
  <strong>METRIC_VALUE: 'dimension2'</strong>
};

// ...

function sendTimeToFirstPaint() {
  var timeToFirstPaint = getTimeToFirstPaintIfSupported();

  if (timeToFirstPaint) {
    var fields = {
      eventCategory: 'Performance',
      eventAction: 'firstpaint',
      // Rounds to the nearest millisecond since
      // event values in Google Analytics must be integers.
      eventValue: Math.round(timeToFirstPaint)
      // Sends this as a non-interaction event,
      // so it doesn't affect bounce rate.
      nonInteraction: true
    }

    <strong>// Sets the event value as a dimension to allow for breaking down the
    // results by individual metric values at reporting time.
    fields[customDimensions.METRIC_VALUE] = String(fields.eventValue);</strong>

    ga('send', 'event', fields);
  }
}

נכון לעכשיו, בממשק האינטרנט של Google Analytics אין אפשרות להציג באופן חזותי את ההתפלגות של ערכי מדדים שרירותיים, אבל אפשר להשתמש ב-Google Analytics Core Reporting API ובספריית Google Charts כדי להריץ שאילתות לגבי התוצאות הגולמיות וליצור היסטוגרמה בעצמנו.

לדוגמה, ההגדרה הבאה של בקשת API שימשה לקבלת התפלגות של ערכי firstpaint במחשב עם worker לא נשלט.

{
  dateRanges: [{startDate: '2016-05-16', endDate: '2016-05-22'}],
  metrics: [{expression: 'ga:totalEvents'}],
  dimensions: [{name: 'ga:dimension2'}],
  dimensionFilterClauses: [
    {
      operator: 'AND',
      filters: [
        {
          dimensionName: 'ga:eventAction',
          operator: 'EXACT',
          expressions: ['firstpaint']
        },
        {
          dimensionName: 'ga:dimension1',
          operator: 'EXACT',
          expressions: ['supported']
        },
        {
          dimensionName: 'ga:deviceCategory',
          operator: 'EXACT',
          expressions: ['desktop']
        }
      ],
    }
  ],
  orderBys: [
    {
      fieldName: 'ga:dimension2',
      orderType: 'DIMENSION_AS_INTEGER'
    }
  ]
}

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

תוצאות של תגובת API (חמש השורות הראשונות)
ga:dimension2 ga:totalEvents
4 3
5 2
6 10
7 8
8 10

משמעויות התוצאות האלה באנגלית פשוטה:

  • היו 3 אירועים שבהם הערך של firstpaint היה 4 אלפיות השנייה
  • היו 2 אירועים שבהם הערך של firstpaint היה 5 אלפיות השנייה
  • היו 10 אירועים שבהם הערך של firstpaint היה 6 אלפיות השנייה
  • היו 8 אירועים שבהם הערך של firstpaint היה 7 אלפיות השנייה
  • היו 10 אירועים שבהם value של firstpaint היה באורך 8 אלפיות השנייה
  • וכו'

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

כך נראתה ההפצה במחשב עם קובץ שירות (service worker) שאינו מבוקר (אבל נתמך):

זמן עד להפצת צבע ראשון במחשב (נתמך)

הזמן החציוני של firstpaint להתפלגות שלמעלה הוא 912 אלפיות השנייה.

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

זמן עד להתפלגות הצבע הראשונה במחשב (מבוקר)

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

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

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

זמן עד להתפלגות הצבע הראשונה במחשב

אחד מהדברים שמעניינים אותי בתוצאות האלה היה העובדה שהתפלגות עם קובץ שירות (service worker) מבוקר עדיין הייתה עקומה בצורת פעמון אחרי העלייה החדה. ציפיתי לעלייה ראשונית גדולה ולהמשך הדרגתי. לא ציפיתי לשיא שני בעקומה.

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

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

כך נראו המוצרים בנייד:

זמן עד להפצת תמונה ראשונה בנייד

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

"...on mobile, הפעלת שרשור של Service Worker ללא פעילות לוקחת זמן רב יותר מאשר במחשב."

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

זמן חציוני עד הצגת תמונה ראשונה (באלפיות השנייה)
סטטוס של קובץ שירות (service worker) מחשב נייד
שליטה ב: 583 1634
נתמך (לא מבוקר) 912 1933

אמנם הבנייה של תצוגות ההתפלגות האלה ארכה זמן ומאמץ יותר מאשר יצירת דוח מותאם אישית ב-Google Analytics, אבל הם מאפשרים לנו להבין טוב יותר איך עובדי שירות משפיעים על ביצועי האתר שלנו יותר מאשר הממוצעים בלבד.

השפעה אחרת של קובצי שירות (Service Workers)

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

גישה אופליין

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

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

בשנתיים האחרונות, ב-IOWA נעשה שימוש בסקריפט של קובץ שירות (service worker) שמזהה היטים שנכשלו ב-Google Analytics כאשר המשתמש לא מחובר לאינטרנט ומפעיל אותם מחדש מאוחר יותר באמצעות הפרמטר qt.

כדי לבדוק אם המשתמש היה אונליין או אופליין, יצרנו מאפיין מותאם אישית בשם Online (אונליין) והגדרתנו לו את הערך navigator.onLine. לאחר מכן הקשבנו לאירועים online ו-offline ועדכנו את המאפיין בהתאם.

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

התראות

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

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

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

הדוח הבא מבוסס על המדד משתמשים ועל המאפיין המותאם אישית 'הרשאת התראות'. הפילוח לפי משתמשים שנכנסו לחשבון בשלב מסוים והדפדפנים שלהם תומכים בהתראות.

אנחנו שמחים לראות שיותר ממחצית מהמשתמשים המחוברים שלנו בחרו לקבל התראות.

מודעות באנר להתקנת אפליקציה

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

ב-IOWA, עקבנו אחרי התדירות שבה ההנחיות האלה הוצגו למשתמש (ואם הן התקבלו) עם הקוד הבא:

window.addEventListener('beforeinstallprompt', function(event) {
  // Tracks that the user saw a prompt.
  ga('send', 'event', {
    eventCategory: 'installprompt',
    eventAction: 'fired'
  });

  event.userChoice.then(function(choiceResult) {
    // Tracks the users choice.
    ga('send', 'event', {
      eventCategory: 'installprompt',
      // `choiceResult.outcome` will be 'accepted' or 'dismissed'.
      eventAction: choiceResult.outcome,
      // `choiceResult.platform` will be 'web' or 'android' if the prompt was
      // accepted, or '' if the prompt was dismissed.
      eventLabel: choiceResult.platform
    });
  });
});

כ-10% מהמשתמשים שראו באנר להתקנת אפליקציה, בחרו להוסיף אותו למסך הבית.

שיפורים אפשריים במעקב (לפעם הבאה)

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

1. מעקב אחרי אירועים נוספים שקשורים לחוויית הטעינה

עקבנו אחרי כמה אירועים שתואמים למדד טכני (למשל, HTMLImportsLoaded, WebComponentsReady וכו'), אבל מכיוון שחלק גדול מהטעינה בוצע באופן אסינכרוני, הנקודה שבה האירועים האלה הופעלו לא בהכרח תאמו לרגע מסוים בחוויית הטעינה הכוללת.

האירוע הראשי שקשור לטעינה שלא עקבנו אחריו (אבל הלוואי שהיה לנו) הוא הנקודה שבה מסך הפתיחה נעלם והמשתמש יכול לראות את תוכן הדף.

2. אחסון מזהה הלקוח של Analytics ב-IndexedDB

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

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

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

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

3. מתן אפשרות ל-Service Worker לדווח על סטטוס אונליין/אופליין

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

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

סיכום

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

הנה כמה מהמסקנות העיקריות של מחקר IOWA:

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

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

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

הערות שוליים

  1. לא הוגן לחלוטין להשוות בין הביצועים של הטמעת המטמון של קובצי השירות שלנו לביצועי האתר שלנו, לבין הביצועים של מטמון HTTP בלבד. מכיוון שביצענו אופטימיזציה של IOWA עבור Service Worker, לא השקענו הרבה זמן באופטימיזציה של מטמון HTTP. אם היו לנו, סביר להניח שהתוצאות היו שונות. למידע נוסף על אופטימיזציה של האתר למטמון HTTP, אפשר לקרוא את המאמר אופטימיזציה יעילה של התוכן.
  2. בהתאם לאופן שבו האתר טוען את הסגנונות והתוכן שלו, יכול להיות שהדפדפן יוכל לצייר לפני שהתוכן או הסגנונות יהיו זמינים. במקרים כאלה, firstpaint עשוי להציג מסך לבן ריק. אם אתם משתמשים ב-firstpaint, חשוב לוודא שהוא תואם לנקודה משמעותית בטעינת משאבי האתר.
  3. מבחינה טכנית, אנחנו יכולים לשלוח היט תזמון (שכברירת מחדל הוא לא אינטראקציה) כדי לתעד את המידע הזה במקום אירוע. למעשה, היטים מסוג תזמון נוספו ל-Google Analytics במיוחד כדי לעקוב אחר מדדי טעינה כמו זה. עם זאת, היטים של תזמון נדגמים באופן משמעותי בזמן העיבוד, ולא ניתן להשתמש בערכים שלהם בפלחים. בהתחשב במגבלות הנוכחיות האלה, אירועים ללא אינטראקציה עדיין מתאימים יותר.
  4. כדי להבין טוב יותר איזה היקף להקצות מאפיין מותאם אישית ב-Google Analytics, מומלץ לעיין בקטע מאפיין מותאם אישית במרכז העזרה של Analytics. חשוב גם להבין את מודל הנתונים של Google Analytics, שכולל משתמשים, ביקורים ואינטראקציות (היטים). למידע נוסף, מומלץ לצפות בשיעור באקדמיה של Analytics בנושא מודל הנתונים של Google Analytics.
  5. המאפיין הזה לא מביא בחשבון משאבים שנטענים באופן מדורג אחרי אירוע הטעינה.