חיפוש אינטראקציות איטיות בשדה

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

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

במדריך הזה תלמדו איך לבצע הערכה מהירה של ה-INP של האתר באמצעות נתוני שטח מדוח חוויית המשתמש ב-Chrome (CrUX) כדי לבדוק אם יש באתר בעיות INP. לאחר מכן, תלמדו איך להשתמש בגרסת השיוך (Attribution) של ספריית ה-JavaScript של משתני אינטרנט — ובתובנות החדשות שהיא מספקת מ-Long Animation Frames API — כדי לאסוף ולפרש נתוני שדות עבור אינטראקציות איטיות באתר שלכם.

מתחילים עם CrUX להערכת ה-INP של האתר

אם אתם לא אוספים נתוני שדות מהמשתמשים באתר שלכם, כדאי להתחיל ב-CrUX. CrUX אוספת נתוני שטח ממשתמשי Chrome אמיתיים שהסכימו לשלוח נתוני טלמטריה.

נתוני CrUX מוצגים במספר תחומים שונים, והם תלויים בהיקף המידע שאתם מחפשים. CrUX יכולה לספק נתונים על INP ועל מדדי ליבה אחרים לבדיקת חוויית המשתמש באתר עבור:

  • דפים נפרדים ומקורות שלמים באמצעות PageSpeed Insights.
  • סוגי דפים. לדוגמה, להרבה אתרי מסחר אלקטרוני יש דפים של פרטי מוצר ודף פרטי מוצר. אתם יכולים לקבל נתוני CrUX לסוגי דפים ייחודיים ב-Search Console.

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

נתוני השדות כפי שמוצגים על ידי CrUX ב-PageSpeed Insights, ומוצגים בהם LCP, INP ו-CLS בשלושת מדדי הליבה לבדיקת חוויית המשתמש באתר ו-TTFB, FCP כמדדי אבחון ו-FID כמדד ליבה לבדיקת חוויית המשתמש באתר שהוצא משימוש.
קריאת נתונים של נתוני CrUX כפי שהיא מופיעה ב-PageSpeed Insights. בדוגמה הזו, נדרש שיפור ב-INP של דף האינטרנט הנתון.

הנתונים האלה שימושיים מפני שהם מציינים אם נתקלת בבעיה. עם זאת, מה ש-CrUX לא יכול לעשות הוא לומר לך מה גורם לבעיות. יש הרבה פתרונות של Real User Monitoring (RUM) שיעזרו לכם לאסוף נתוני שדות מהמשתמשים באתר שלכם כדי לענות על כך. אפשרות אחת היא לאסוף את נתוני השדות האלה בעצמכם באמצעות ספריית ה-JavaScript של vitals.

איסוף נתוני שדות באמצעות ספריית web-vitals ב-JavaScript

ספריית ה-JavaScript של web-vitals היא סקריפט שאפשר לטעון לאתר כדי לאסוף נתוני שדות ממשתמשי האתר. אפשר להשתמש בו כדי לתעד כמה מדדים, כולל INP בדפדפנים שתומכים בכך.

תמיכה בדפדפן

  • 96
  • 96
  • x
  • x

מקור

ניתן להשתמש בגרסת ה-build הרגילה של ספריית vitals באינטרנט כדי לקבל נתוני INP בסיסיים ממשתמשים בשדה:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  console.log(name);    // 'INP'
  console.log(value);   // 512
  console.log(rating);  // 'poor'
});

צריך לשלוח את הנתונים האלה למקום כלשהו כדי לנתח את נתוני השדות מהמשתמשים שלכם:

import {onINP} from 'web-vitals';

onINP(({name, value, rating}) => {
  // Prepare JSON to be sent for collection. Note that
  // you can add anything else you'd want to collect here:
  const body = JSON.stringify({name, value, rating});

  // Use `sendBeacon` to send data to an analytics endpoint.
  // For Google Analytics, see https://github.com/GoogleChrome/web-vitals#send-the-results-to-google-analytics.
  navigator.sendBeacon('/analytics', body);
});

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

להתקדם יותר עם מודל השיוך (Attribution) של ספריית משתני האינטרנט

מודל השיוך (Attribution) של ספריית 'מדדי האתרים' מציג נתונים נוספים שאפשר לקבל ממשתמשים בשטח כדי לעזור לכם לפתור בעיות טובות יותר באינטראקציות בעייתיות שמשפיעות על ה-INP של האתר. ניתן לגשת לנתונים האלה דרך האובייקט attribution שמוצג ב-method onINP() של הספרייה:

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, rating, attribution}) => {
  console.log(name);         // 'INP'
  console.log(value);        // 56
  console.log(rating);       // 'good'
  console.log(attribution);  // Attribution data object
});
איך מוצגים יומני המסוף מספריית Web-vitals המסוף בדוגמה הזו מציג את שם המדד (INP), ערך ה-INP (56), שבו הערך נמצא בין ספי ה-INP (טוב) ואת ביטים השונים של המידע המוצגים באובייקט השיוך, כולל רשומות מ-Long Animation Frame API.
איך נתונים מספריית vitals של דפי אינטרנט מופיעים במסוף.

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

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

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

מפתח אובייקט attribution נתונים
interactionTarget סלקטור ב-CSS שמפנה אל הרכיב שיצר את ערך ה-INP של הדף. לדוגמה: button#save.
interactionType סוג האינטראקציה – קליקים, הקשות או קלט מהמקלדת.
inputDelay* העיכוב בקלט של האינטראקציה.
processingDuration* הזמן שעובר מהרגע שבו ה-event listener הראשון התחיל לפעול בתגובה לאינטראקציה של המשתמש ועד לסיום העיבוד של כל ה-event listener.
presentationDelay* עיכוב ההצגה של האינטראקציה. הזמן הזה מתרחש החל מרגע שהגורמים המטפלים באירועים מסיימים לצבוע את הפריים הבא.
longAnimationFrameEntries* רשומות מ-LoAF שמשויכות לאינטראקציה. במידע נוסף מופיע מידע נוסף בשלב הבא.
*חדש בגרסה 4

החל מגרסה 4 של ספריית 'המיטב של האינטרנט', תוכלו לקבל תובנות מעמיקות יותר לגבי אינטראקציות בעייתיות באמצעות הנתונים שהיא מספקת באמצעות פירוטי שלב ה-INP (עיכוב בקלט, משך העיבוד ועיכוב ההצגה) ו-Long Animation Frame API (LoAF).

ממשק ה-API של מסגרת אנימציה ארוכה (LoAF)

תמיכה בדפדפן

  • 123
  • 123
  • x
  • x

מקור

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

גרסת ה-build של השיוך (Attribution) של ספריית vitals חושפת מערך של רשומות LoAF מתחת למפתח longAnimationFrameEntries של האובייקט attribution. בטבלה הבאה מפורטים כמה קטעי נתונים עיקריים שאפשר למצוא בכל רשומה של LoAF:

מפתח אובייקט של רשומת LoAF נתונים
duration משך הזמן של מסגרת האנימציה הארוכה, עד לסיום הפריסה, אבל לא כולל ציור והרכבה.
blockingDuration משך הזמן הכולל בפריים שבו הדפדפן לא הצליח להגיב במהירות בגלל משימות ארוכות. זמן החסימה הזה יכול לכלול משימות ארוכות שמפעילות JavaScript, וגם כל משימת עיבוד ארוכה לאחר מכן במסגרת.
firstUIEventTimestamp חותמת הזמן של שעת ההוספה של האירוע לתור במהלך הפריים. הנתונים האלה יכולים להועיל לחישוב ההתחלה של עיכוב בקלט של אינטראקציה.
startTime חותמת הזמן של ההתחלה של הפריים.
renderStart מתי התחילה עבודת הרינדור של המסגרת. המספר הזה כולל כל קריאה חוזרת (callback) של requestAnimationFrame (וגם ResizeObserver קריאות חוזרות (callback), אם רלוונטי), אבל יכול להיות לפני תחילת העבודה של סגנון או פריסה.
styleAndLayoutStart כשמתבצעת עבודת סגנון/פריסה בפריים. האפשרות הזו יכולה להיות שימושית כשרוצים להבין את משך הזמן של עבודת הסגנון/הפריסה, כשמנסים למצוא חותמות זמן זמינות אחרות.
scripts מערך פריטים שמכילים פרטי ייחוס של סקריפט שתורמים ל-INP של הדף.
הדמיה של מסגרת אנימציה ארוכה לפי מודל LoAF.
תרשים של התזמונים של מסגרת אנימציה ארוכה בהתאם ל-LoAF API (פחות blockingDuration).

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

מפתח אובייקט של שיוך לסקריפט נתונים
invoker הגורם המזמין. הערך הזה עשוי להשתנות בהתאם לסוג ה-Invoker שמתואר בשורה הבאה. דוגמאות לאופרטורים יכולים להיות ערכים כמו 'IMG#id.onload', 'Window.requestAnimationFrame' או 'Response.json.then'.
invokerType סוג ה-Invoker. יכול להיות 'user-callback', 'event-listener', 'resolve-promise', 'reject-promise', 'classic-script' או 'module-script'.
sourceURL כתובת ה-URL של הסקריפט שממנו הגיעה מסגרת האנימציה הארוכה.
sourceCharPosition מיקום התו בסקריפט שזוהה על ידי sourceURL.
sourceFunctionName שם הפונקציה בסקריפט שזוהה.

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

מדידה וזיהוי של הסיבות הנפוצות לאינטראקציות איטיות

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

עיבודים ארוכים

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5
});

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {processingDuration} = attribution; // 512.5

  // Get the longest script from LoAF covering `processingDuration`:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Get attribution for the long-running event handler:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

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

  • הרכיב ו-event listener הרשום שלו.
  • קובץ הסקריפט – ומיקום התווים בתוכו – שמכילים את הקוד של הגורם המטפל באירועים לטווח ארוך.
  • שם הפונקציה.

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

עיכובים בהזנת קלט ארוך

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536
});

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

האם זה היה בזמן טעינת הדף?

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

  if (script) {
    // Invoker types can describe if script eval blocked the main thread:
    const {invokerType} = script;    // 'classic-script' | 'module-script'
    const {sourceLocation} = script; // 'https://example.com/app.js'
  }
});

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

האם זה קרה אחרי טעינת הדף?

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {inputDelay} = attribution; // 125.59439536

  // Get the longest script from the first LoAF entry:
  const loaf = attribution.longAnimationFrameEntries[0];
  const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

  if (script) {
    const {invokerType} = script;        // 'user-callback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

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

  • 'user-callback' מציין שמשימת החסימה הייתה setInterval, setTimeout או אפילו requestAnimationFrame.
  • 'event-listener' מציין שמשימת החסימה הייתה מבוססת על קלט קודם שהיה בהמתנה בתור ועדיין בתהליך עיבוד.
  • המשמעות של 'resolve-promise' ו-'reject-promise' היא שמשימת החסימה הגיעה מעבודה אסינכרונית שהופעלה קודם, והסתיימה או נדחתה במועד שבו המשתמש ניסה לבצע אינטראקציה בדף, מה שעכב את האינטראקציה.

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

עיכובים ארוכים בהצגת המודעות

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691
});

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

עבודות יקרות של סגנון ופריסה

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

import {onINP} from 'web-vitals/attribution';

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 113.32307691

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

  // Get necessary timings:
  const {startTime} = loaf; // 2120.5
  const {duration} = loaf;  // 1002

  // Figure out the ending timestamp of the frame (approximate):
  const endTime = startTime + duration; // 3122.5

  // Get the start timestamp of the frame's style/layout work:
  const {styleAndLayoutStart} = loaf; // 3011.17692309

  // Calculate the total style/layout duration:
  const styleLayoutDuration = endTime - styleAndLayoutStart; // 111.32307691

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running style and layout operation:
    const {invokerType} = script;        // 'event-listener'
    const {invoker} = script;            // 'BUTTON#update.onclick'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

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

התקשרות חזרה לטווח ארוך של requestAnimationFrame

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

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

onINP(({name, value, attribution}) => {
  const {presentationDelay} = attribution; // 543.1999999880791

  // Get the longest script from the last LoAF entry:
  const loaf = attribution.longAnimationFrameEntries.at(-1);
  const script = loaf?.scripts.sort((a, b) => b.duration - a.duration)[0];

  // Get the render start time and when style and layout began:
  const {renderStart} = loaf;         // 2489
  const {styleAndLayoutStart} = loaf; // 2989.5999999940395

  // Calculate the `requestAnimationFrame` callback's duration:
  const rafDuration = styleAndLayoutStart - renderStart; // 500.59999999403954

  if (script) {
    // Get attribution for the event handler that triggered
    // the long-running requestAnimationFrame callback:
    const {invokerType} = script;        // 'user-callback'
    const {invoker} = script;            // 'FrameRequestCallback'
    const {sourceURL} = script;          // 'https://example.com/app.js'
    const {sourceCharPosition} = script; // 83
    const {sourceFunctionName} = script; // 'update'
  }
});

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

סיכום

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

תמונה ראשית (Hero) מ-Unbounce, מאת פדריקו רסיני.