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

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

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

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

תחילה כדאי להשתמש ב-CrUX כדי להעריך את INP של האתר

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

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

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

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

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

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

איסוף נתונים מהשטח באמצעות ספריית JavaScript‏ web-vitals

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

תמיכה בדפדפנים

  • Chrome: ‏ 96.
  • Edge: ‏ 96.
  • Firefox: לא נתמך.
  • Safari: לא נתמך.

מקור

אפשר להשתמש בגרסה הרגילה של ה-build של ספריית מדדי הווידאו כדי לקבל נתוני 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. כאן נכנסת לתמונה הגרסה של ספריית Web Vitals עם שיוך (Attribution).

שיפורים נוספים באמצעות גרסה של ספריית מדדי ה-Web Vitals עם שיוך

גרסת build של השיוך בספריית מדדי ביצועי האתר מציגה נתונים נוספים שאפשר לקבל ממשתמשים בשטח, כדי לעזור לכם לפתור בעיות באינטראקציות שמשפיעות על מדד INP של האתר. אפשר לגשת לנתונים האלה דרך האובייקט attribution שמופיע בשיטה 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
});
איך יופיעו יומני המסוף מהספרייה של מדדי הליבה לבדיקת חוויית המשתמש באתר. במסוף שבדוגמאות האלה מוצגים שם המדד (INP), ערך ה-INP (56), המיקום של הערך הזה ביחס לסף ה-INP (טוב) וקטעי המידע השונים שמוצגים באובייקט השיוך, כולל רשומות מ-Long Animation Frames API.
כך נתונים מספריית מדדי הווידאו מופיעים במסוף.

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

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

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

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

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

Long Animation Frames API‏ (LoAF)

תמיכה בדפדפנים

  • Chrome: ‏ 123.
  • Edge: ‏ 123.
  • Firefox: לא נתמך.
  • Safari: לא נתמך.

מקור

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

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

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

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

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

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

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

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

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

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

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 הרשום שלו.
  • קובץ הסקריפט – ומיקום התו בתוכו – שמכיל את הקוד של גורם הטיפול באירועים שפועל לאורך זמן.
  • שם הפונקציה.

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

עיכובים ארוכים לאחר קלט

פונקציות טיפול באירועים שמתמשכות זמן רב הן נפוצות, אבל יש חלקים אחרים של האינטראקציה שצריך להביא בחשבון. חלק אחד מתרחש לפני משך העיבוד, והוא נקרא עיכוב קלט. זהו הזמן שחולף מהרגע שבו המשתמש יוזם את האינטראקציה ועד לרגע שבו פונקציות ה-call back של טיפול האירועים מתחילות לפעול. הזמן הזה מתרחש כשהשרשור הראשי כבר מעבד משימה אחרת. גרסה של שיוך בספריית מדדי ה-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', אפשר להסיק שהזמן להערכת הסקריפטים באתר ארוך והם חוסמים את הליבה למשך זמן מספיק כדי לעכב אינטראקציות. כדי לקצר את זמן החסימה, אפשר לפצל את הסקריפטים לחבילות קטנות יותר, לדחות את הטעינה של קוד שלא נעשה בו שימוש בשלב הראשון לזמן מאוחר יותר ולבדוק את האתר כדי לאתר קוד שלא נעשה בו שימוש שאפשר להסיר לגמרי.

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

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

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'
  }
});

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

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

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

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

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

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

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

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

עבודות יקרות של עיצוב ופריסה

עיכובים ארוכים בהצגה עשויים לנבוע מחישוב מחדש של סגנונות ומעבודות פריסה יקרות שנובעות מכמה סיבות, כולל בוחרי CSS מורכבים וגדלים גדולים של DOM. אתם יכולים למדוד את משך הזמן של העבודה הזו באמצעות זמני LoAF שמוצגים בספרייה של מדדי ה-Web 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 כדי לחשב את משך הזמן המדויק של העבודה הזו. לשם כך, קובעים את שעת הסיום של הפריים ומחסרים ממנה את חותמת הזמן של תחילת העבודה על העיצוב והפריסה.

קריאות חזרה ממושכות של requestAnimationFrame

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

אם העבודה שבוצעה בהן מורכבת, יכול להיות שהשלמת הקריאות החוזרות האלה תימשך זמן רב. אם אתם חושדים שערכים גבוהים של עיכוב הצגה נובעים מהעבודה שלכם עם requestAnimationFrame, אתם יכולים להשתמש בנתוני LoAF שמוצגים על ידי ספריית web-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 Vitals (או ספק RUM), מאפשר לכם לדעת בוודאות רבה יותר אילו אינטראקציות הן הבעייתיות ביותר, ולאחר מכן לשכפל אינטראקציות בעייתיות במעבדה ולתקן אותן.

התמונה הראשית (Hero) מ-Unsplash, מאת Federico Respini.