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

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

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

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

כדאי להתחיל עם 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 כמדד שהוצא משימוש של Core Web Vitals.
קריאה של נתוני CrUX כפי שמוצגים ב-PageSpeed Insights. בדוגמה הזו, נדרש שיפור בערך ה-INP של דף האינטרנט שצוין.

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

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

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

Browser Support

  • Chrome: 96.
  • Edge: 96.
  • Firefox: 144.
  • Safari: not supported.

Source

אפשר להשתמש בגרסה הרגילה של ספריית web-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. כאן נכנס לתמונה ייחוס הבנייה של ספריית Web Vitals.

איך להפיק את המרב מהשיוך של ספריית web-vitals

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

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

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

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

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

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

‫Long Animation Frames API ‏ (LoAF)

Browser Support

  • Chrome: 123.
  • Edge: 123.
  • Firefox: not supported.
  • Safari: not supported.

Source

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

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

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

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

מפתח אובייקט של שיוך (Attribution) סקריפט נתונים
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 כדי לזהות כמה מהגורמים לאינטראקציות איטיות.

משך עיבוד ארוך

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

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

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

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

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

השהיות ארוכות לאחר קלט

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

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

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

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

קריאות חוזרות (callback) ממושכות של 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.toSorted((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'
  }
});

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

סיכום

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

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