מהירות תגובה נמוכה לאינטראקציות יוצרת רושם שהדף איטי או אפילו לא תקין בכלל. מהירות התגובה לאינטראקציה באתר (INP) היא מדד שמבוסס על Event Timing API. הוא מודד את האינטראקציה הכי גרועה (בניכוי כמה חריגים) כדי למדוד את מהירות התגובה של הדף.
זיהוי שורש הבעיה של דף אינטרנט שלא מגיב יכול להיות מסובך, במיוחד כי הוא תלוי באינטראקציות של המשתמשים ובתנאי הסביבה, כמו יכולות המכשיר ותנאי הרשת. לכן קשה יותר לאבחן את הבעיה בהשוואה לתרחיש שחוזר על עצמו וניתן לחיזוי, כמו טעינת דף. נתוני מעבדה משכפלים רק קבוצת משנה קטנה של תרחישים של משתמשים אמיתיים, ולכן חשוב למדוד את הגורמים ל-INP איטי בשטח.
Event Timing API מאפשר לפצל את משך הזמן של INP לשלושה חלקים: עיכוב בקלט (עיבוד שכבר מתרחש כשהאינטראקציה מתרחשת), משך העיבוד (עיכובים כתוצאה ישירה מהאינטראקציה) ועיכוב בהצגה (עיכובים שנובעים מעיבוד הפריים הבא אחרי האינטראקציה). כך אפשר לזהות אם הבעיה היא בקוד אחר, בקוד ה-JavaScript של האינטראקציה או בעיבוד של עדכוני העיבוד בדפדפן, במקום לקפוץ ישר לקוד האינטראקציה.
אפשר לאסוף תובנות נוספות לגבי JavaScript, חישוב מחדש של סגנון ופריסה שמעכבים אינטראקציה. מעקב ביצועים מלא באמצעות JS Self-Profiling API הוא פתרון כבד שעלול לגרום לבעיות בביצועים. Long Animation Frames API הוא API קל משקל שאפשר להשתמש בו בשטח כדי לזהות JavaScript שפועל לאט, ולהבחין בין עלויות של חישוב מחדש של סגנון לבין עלויות של פריסה במהלך אינטראקציות של INP:
- סגנון ופריסה שנכפו ברמת הסקריפט (
forcedStyleDurationו-forcedLayoutDuration): דיווח על חישובים מחדש של סגנונות סינכרוניים (כמו קריאה ל-getComputedStyle()אחרי שינויים ב-DOM) ופריסות/הזרמות מחדש שנכפו (כמו קריאה ל-getBoundingClientRect()או ל-offsetWidthאחרי שינויים) בתוך סקריפט שפועל במהלך העיכוב בקלט או משך העיבוד. - סגנון העיבוד והפריסה ברמת הפריימים (
styleDurationו-layoutDuration): דיווח על הזמן שהושקע בחישוב מחדש של הסגנונות לעומת עדכון הפריסה במהלך עדכון העיבוד של הפריימים, כדי להסביר את הערך הגבוה של העיכוב בהצגה.
חשוב להבחין בין חישוב מחדש של סגנון לבין פריסה, כי יש להם סיבות שורש ופתרונות שונים: משך זמן ארוך של סגנון מצביע על התאמה יקרה של סלקטור ב-CSS או על ביטול תוקף של סגנון רחב (אפשר לפתור את הבעיה על ידי פישוט הסלקטורים או צמצום היקף הכללים), ואילו משך זמן ארוך של פריסה מצביע על חישובים גיאומטריים יקרים או על שינוי פריסה סינכרוני (אפשר לפתור את הבעיה על ידי קריאות DOM באצווה לפני כתיבה, פישוט מבנה ה-DOM או שימוש בהכלה של CSS).
איך מטמיעים
חישוב ה-INP מ-Event Timing API הגולמי הוא מסובך ויש לו כמה ניואנסים. מומלץ להשתמש בכלי או בספרייה של RUM כדי לאסוף את הנתונים האלה.
web-vitals היא ספריית קוד פתוח של Google שמחשבת את מדדי Core Web Vitals, כולל INP, וכוללת גם חלקי משנה ונתונים של פריים אנימציה עם טעינה ארוכה (LoAF) לאינטראקציה של INP.
איך מקבלים שיוכים לאינטראקציות של INP באמצעות ספריית web-vitals
הספרייה web-vitals היא ספרייה קטנה שמשמשת למדידת מדדי Core Web Vitals ומדדי ביצועים אחרים. אפשר להשתמש בפונקציה onINP() כדי לזהות את האינטראקציה האיטית ביותר. היא כוללת מידע על חלקי המשנה של ה-INP, סקריפטים שהופעלו במהלך האינטראקציה ומשכי הזמן של הסגנון והפריסה באמצעות Long Animation Frames API.
// Use the attribution build to get Long Animation Frame data
// alongside the INP metric value.
import { onINP } from 'web-vitals/attribution';
onINP((metric) => {
const { attribution } = metric;
const longestScript = attribution.longestScript;
// Sum rendering-phase style and layout durations across all LoAF entries
// intersecting the INP interaction (primarily explains presentationDelay).
let renderStyleDuration = 0;
let renderLayoutDuration = 0;
for (const entry of attribution.longAnimationFrameEntries) {
renderStyleDuration += entry.styleDuration ?? 0;
renderLayoutDuration += entry.layoutDuration ?? 0;
}
// Beacon script, style, and layout attribution for the INP interaction,
// so you can identify the root cause in production.
navigator.sendBeacon(
'/analytics',
JSON.stringify({
name: 'INP',
value: metric.value,
// These fields give the INP subparts:
inputDelay: attribution.inputDelay,
presentationDelay: attribution.presentationDelay,
processingDuration: attribution.processingDuration,
interactionTarget: attribution.interactionTarget,
// These fields identify which script function was responsible
// for the longest processing during the INP interaction.
invokerType: longestScript?.entry?.invokerType,
sourceURL: longestScript?.entry?.sourceURL,
sourceFunctionName: longestScript?.entry?.sourceFunctionName,
sourceCharPosition: longestScript?.entry?.sourceCharPosition,
// subpart indicates which phase (input delay, processing, or
// presentation delay) the longest script overlapped with most.
subpart: longestScript?.subpart,
intersectingDuration: longestScript?.intersectingDuration,
// Synchronous style and layout work forced inside the longest script
// (with forcedStyleAndLayoutDuration as a combined fallback):
forcedStyleDuration: longestScript?.entry?.forcedStyleDuration,
forcedLayoutDuration: longestScript?.entry?.forcedLayoutDuration,
forcedStyleAndLayoutDuration: longestScript?.entry?.forcedStyleAndLayoutDuration,
// Rendering-phase style and layout work across the interaction's frames
// (with totalStyleAndLayoutDuration as a combined fallback):
renderStyleDuration,
renderLayoutDuration,
totalStyleAndLayoutDuration: attribution.totalStyleAndLayoutDuration
})
);
});
שיטות מומלצות
- מומלץ להשתמש בחלקי המשנה של INP בהתחלה כדי לזהות אם העיכוב נובע מהרצה של JavaScript (עיכוב בקלט), מהגורמים המטפלים באירועים של JavaScript לאינטראקציה (משך העיבוד) או מהעיבוד הבא (עיכוב בהצגה).
- כדאי לנסות לזהות את ה-JavaScript שגורם לחסימה הכי גדולה כפרט נוסף, במיוחד לגבי עיכוב בקלט ומשך העיבוד.
- מומלץ להבחין בין חישוב מחדש של סגנון (
styleDuration,forcedStyleDuration) לבין פריסה (layoutDuration,forcedLayoutDuration) כשמנתחים משך עיבוד ארוך או עיכוב בהצגה: זמני סגנון ארוכים מצביעים על סלקטורים ב-CSS יקרים או על ביטולים נרחבים, ואילו זמני פריסה ארוכים מצביעים על צווארי בקבוק בגיאומטריה של DOM או על שינויים תכופים בפריסה סינכרונית. - מומלץ להשתמש ב-Long Animation Frames API כדי לקבל את הפרטים הנוספים האלה, ולא בחלופות כמו JS Self-Profiling API, שדורש יותר משאבים בזמן הריצה.
- מומלץ להשתמש בספרייה
web-vitalsאם אין פתרון RUM אחר. הוא יכול לזהות את האינטראקציה של ה-INP, והוא כולל מידע על חלקי המשנה ועל הסקריפטים שהופעלו במהלך האינטראקציה (באמצעות Long Animation Frames API). - מומלץ לשלוח את המידע הנדרש לשירות ניתוח נתונים במקום לתעד אותו באופן מקומי.
תמיכה בדפדפנים ושיטות חלופיות
Event Timing API זמין ברוב הדפדפנים המודרניים, והוא נדרש כדי לחשב את ה-INP ואת חלקי המשנה של ה-INP. בדפדפנים שלא תומכים ב-API הזה, אי אפשר למדוד את ה-INP.
Long Animation Frames API מספק פרטים אופציונליים נוספים. אפשר להשתמש בו בבטחה בלי חלופות. ברוב המקרים, ההזדמנויות לשיפור הביצועים שהוא מזהה יהיו רלוונטיות גם לדפדפנים אחרים.
אם יעד Baseline תומך ב-Long Animation Frames API (long-animation-frames) אבל לא תומך במאפייני משך זמן נפרדים של סגנון ופריסה (styleDuration ו-layoutDuration ב-PerformanceLongAnimationFrameTiming, או forcedStyleDuration ו-forcedLayoutDuration ב-PerformanceScriptTiming), צריך לחזור לתזמונים המשולבים של סגנון ופריסה:
- כדי לבצע עבודה סינכרונית מאולצת של סגנון ופריסה בתוך סקריפטים, צריך להשתמש ב-
script.forcedStyleAndLayoutDurationב-PerformanceScriptTiming. - כדי לשלב בין סגנון ופריסה, משתמשים ב-
metric.attribution.totalStyleAndLayoutDurationב-web-vitals/attribution(או מחשבים את(entry.paintTime || entry.startTime + entry.duration) - entry.styleAndLayoutStartבכל רשומה שלPerformanceLongAnimationFrameTiming).