Long Animation Frames API (LoAF – מבוטא Lo-Af) הוא עדכון ל-Long Tasks API שמאפשר הבנה טובה יותר של עדכונים איטיים בממשק המשתמש (UI). התכונה הזו יכולה להיות שימושית לזיהוי פריימים איטיים של אנימציה שיש סיכוי גבוה שהם ישפיעו על המדד מאינטראקציה ועד הצגת התגובה (INP) של מדדי הליבה לבדיקת חוויית המשתמש באתר, שמודד את הרספונסיביות, או לזיהוי תנודות אחרות בממשק המשתמש שמשפיעות על החלקות.
סטטוס ה-API
אחרי גרסת מקור לניסיון מ-Chrome 116 עד Chrome 122, LoAF API שוחרר מ-Chrome 123.
רקע: Long Tasks API
Long Animation Frames API הוא חלופה ל-Long Tasks API, שזמין ב-Chrome כבר זמן מה (מאז Chrome 58). כפי שרואים מהשם, Long Task API מאפשר לכם לעקוב אחרי משימות ארוכות – משימות שמשתלטות על השרשור הראשי למשך 50 אלפיות השנייה או יותר. אפשר לעקוב אחרי משימות ארוכות באמצעות הממשק PerformanceLongTaskTiming
, עם PeformanceObserver
:
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: 'longtask', buffered: true });
סביר להניח שמשימות ארוכות יגרמו לבעיות בתגובה. אם משתמש מנסה ליצור אינטראקציה עם דף – לדוגמה, ללחוץ על לחצן או לפתוח תפריט – אבל הפעילות הראשית כבר מטפלת במשימה ארוכה, האינטראקציה של המשתמש מתעכבת עד שהמשימה תושלם.
כדי לשפר את המהירות של התגובה, מומלץ לעיתים קרובות לפצל משימות ארוכות. אם כל משימה ארוכה תפוצל לסדרה של כמה משימות קצרות יותר, יכול להיות שתוכלו לבצע משימות חשובות יותר ביניהן כדי למנוע עיכובים משמעותיים בתגובה לאינטראקציות.
לכן, כשמנסים לשפר את המהירות של התגובה, לרוב הניסיון הראשון הוא להריץ מעקב ביצועים ולבדוק משימות ארוכות. אפשר לעשות זאת באמצעות כלי ביקורת מבוסס-מעבדה כמו Lighthouse (שיש בו בדיקה של הימנעות ממשימות שנדרש להן משך זמן ארוך ב-thread הראשי), או על ידי בדיקת משימות ארוכות בכלי הפיתוח ל-Chrome.
בדיקות במעבדה הן לרוב מקום גרוע להתחלה לזיהוי בעיות בתגובה, כי יכול להיות שהכלים האלה לא יכללו אינטראקציות – ואם כן, הן יהיו קבוצת משנה קטנה של אינטראקציות אפשריות. באופן אידיאלי, כדאי למדוד את הגורמים לאינטראקציות איטיות בשטח.
חסרונות של Long Tasks API
מדידת משימות ארוכות בשטח באמצעות מכשיר למדידת ביצועים היא שימושית רק במידה מסוימת. בפועל, הוא לא מספק הרבה מידע מעבר לעובדה שהתרחשה משימה ארוכה וכמה זמן היא נמשכה.
לרוב, כלים למעקב אחר משתמשים אמיתיים (RUM) משתמשים בנתונים האלה כדי לזהות מגמות במספר או במשך המשימות הארוכות, או כדי לזהות את הדפים שבהם הן מתרחשות. אבל ללא הפרטים הבסיסיים לגבי הגורם למשימות הארוכות, השימוש בנתונים האלה מוגבל. ל-Long Tasks API יש רק מודל שיוך בסיסי, שבמקרה הטוב מודיע רק על המאגר שבו התרחשה המשימה הארוכה (המסמך ברמת העליונה או <iframe>
), אבל לא על הסקריפט או הפונקציה שהפעילו אותה, כפי שמוצג ברשומה טיפוסית:
{
"name": "unknown",
"entryType": "longtask",
"startTime": 31.799999997019768,
"duration": 136,
"attribution": [
{
"name": "unknown",
"entryType": "taskattribution",
"startTime": 0,
"duration": 0,
"containerType": "window",
"containerSrc": "",
"containerId": "",
"containerName": ""
}
]
}
גם ה-API של המשימות הארוכות הוא תצוגה חלקית, כי יכול להיות שהוא לא יכלול משימות חשובות מסוימות. חלק מהעדכונים – כמו רינדור – מתרחשים במשימות נפרדות, שבאופן אידיאלי צריך לכלול יחד עם הביצוע הקודם שגרם לעדכון הזה, כדי למדוד במדויק את 'סך העבודה' של האינטראקציה הזו. פרטים נוספים על המגבלות של שימוש במשימות מופיעים בקטע 'איפה משימות ארוכות נכשלות' במאמר ההסבר.
הבעיה האחרונה היא שמדידה של משימות ארוכות מדווחת רק על משימות ספציפיות שנמשכות יותר ממגבלת 50 אלפיות השנייה. פריים של אנימציה יכול להיות מורכב מכמה משימות שקטנות מהמגבלה של 50 אלפיות השנייה, אבל יחד הן עדיין חוסמות את היכולת של הדפדפן לבצע רינדור.
Long Animation Frames API
Long Animation Frames API (LoAF) הוא ממשק API חדש שמטרתו לטפל בחלק מהחסרונות של Long Tasks API, כדי לאפשר למפתחים לקבל תובנות מעשיות יותר שיעזרו להם לטפל בבעיות של תגובה מהירה ולשפר את INP, וגם לקבל תובנות לגבי בעיות של חלקות.
מהירות תגובה טובה פירושה שהדף מגיב במהירות לאינטראקציות שמתבצעות איתו. כדי לעשות זאת, צריך להיות אפשרות לצייר את כל העדכונים הנחוצים למשתמש בזמן, ולהימנע מחסימה של העדכונים האלה. ב-INP, מומלץ להגיב תוך 200 אלפיות השנייה או פחות, אבל לעדכונים אחרים (לדוגמה, אנימציות) גם 200 אלפיות השנייה עשויות להיות זמן ארוך מדי.
Long Animation Frames API היא גישה חלופית למדידת זמן העבודה של חסימה. במקום למדוד את המשימות הנפרדות, Long Animation Frames API – כפי ששמו מרמז – מודד פריימים ארוכים של אנימציה. מסגרת אנימציה ארוכה היא מצב שבו עדכון הרינדור מתעכב מעבר ל-50 אלפיות השנייה (זהו הסף גם ל-Long Tasks API).
הזמן של פריימים ארוכים של אנימציה נמדד מתחילת המשימות שדורשות רינדור. אם המשימה הראשונה בפריים אנימציה ארוך פוטנציאלי לא דורשת רינדור, פריים האנימציה הארוך מסתיים עם השלמת המשימה שלא דורשת רינדור, ופריים אנימציה ארוך פוטנציאלי חדש מתחיל עם המשימה הבאה. פריים של אנימציה ארוכה שלא עבר רינדור עדיין נכלל ב-Long Animation Frames API אם הוא ארוך מ-50 אלפיות השנייה (עם זמן renderStart
של 0), כדי לאפשר מדידה של עבודה שעלולה לחסום משימות אחרות.
אפשר לצפות בפריימים ארוכים של אנימציה באופן דומה למשימות ארוכות עם PerformanceObserver
, אבל במקום זאת בודקים את הסוג long-animation-frame
:
const observer = new PerformanceObserver((list) => {
console.log(list.getEntries());
});
observer.observe({ type: 'long-animation-frame', buffered: true });
אפשר גם לשלוח שאילתה על פריימים קודמים של אנימציה ארוכה דרך ציר הזמן של הביצועים באופן הבא:
const loafs = performance.getEntriesByType('long-animation-frame');
עם זאת, יש maxBufferSize
של רשומות ביצועים, אחריו רשומות חדשות יותר נמחקות, ולכן הגישה של PerformanceObserver היא הגישה המומלצת. גודל המאגר הזמני long-animation-frame
מוגדר ל-200, כמו ב-long-tasks
.
היתרונות של הצגת מסגרות במקום משימות
היתרון העיקרי של התבוננות בנושא מנקודת מבט של פריים במקום מנקודת מבט של משימות הוא שאפשר ליצור אנימציה ארוכה מכל מספר של משימות שהתוצאה המצטברת שלהן היא פריים של אנימציה ארוכה. כך פותרים את הנקודה האחרונה שצוינה קודם, שבה ייתכן ש-Long Tasks API לא יציג את הסכום של משימות קטנות רבות שגורמות לחסימת הרינדור לפני פריים של אנימציה.
יתרון נוסף של התצוגה החלופית הזו במשימות ארוכות הוא היכולת לספק פירוט של תזמון של כל המסגרת. במקום לכלול רק startTime
ו-duration
, כמו ב-Long Tasks API, ב-LoAF יש פירוט מפורט הרבה יותר של החלקים השונים של משך הפריימים.
חותמות זמן ומשכי זמן של פריים
startTime
: שעת ההתחלה של מסגרת האנימציה הארוכה ביחס לשעת ההתחלה של הניווט.duration
: משך הזמן של פריים האנימציה הארוך (לא כולל זמן הצגה).renderStart
: שעת ההתחלה של מחזור הרינדור, שכולל קריאות חזרה (callbacks) שלrequestAnimationFrame
, חישוב סגנון ופריסה, קריאות חזרה של משקיף שינוי הגודל ומשקיף הצטלבות.styleAndLayoutStart
: תחילת פרק הזמן שבו בוצעו חישובי סגנון פריסת הדף.firstUIEventTimestamp
: השעה של אירוע ממשק המשתמש הראשון (עכבר/מקלדת וכו') שעובד במהלך המסגרת הזו. הערה: ייתכן שהאירועfirstUIEventTimestamp
יופיע בפריים קודם אם היה עיכוב בין מועד האירוע לבין מועד העיבוד שלו.blockingDuration
: משך הזמן הכולל באלפיות השנייה שבו מסגרת האנימציה תחסום את העיבוד של קלט או משימות אחרות בעדיפות גבוהה.
הסבר על blockingDuration
מסגרת אנימציה ארוכה עשויה להיות מורכבת מכמה משימות. הערך של blockingDuration
הוא הסכום של משכי הזמן של משימות שנמשכות יותר מ-50 אלפיות השנייה (כולל משך העיבוד הסופי של המשימה הארוכה ביותר).
לדוגמה, אם פריים ארוך של אנימציה מורכב משתי משימות של 55 אלפיות השנייה ו-65 אלפיות השנייה, ואחריה עיבוד של 20 אלפיות השנייה, הערך של duration
יהיה כ-140 אלפיות השנייה, והערך של blockingDuration
יהיה (55 - 50) + (65 + 20 - 50) = 40 אלפיות השנייה. במשך 40 אלפיות השנייה במסגרת האנימציה באורך 140 אלפיות השנייה, המסגרת נחשבה חסומה לטיפול בקלט.
האם לבדוק את duration
או את blockingDuration
במסך רגיל של 60 הרץ, הדפדפן ינסה לתזמן פריים לפחות כל 16.66 אלפיות השנייה (כדי להבטיח עדכונים חלקים), או אחרי משימה בעדיפות גבוהה כמו טיפול בקלט (כדי להבטיח עדכונים רספונסיביים). עם זאת, אם אין קלט או משימות אחרות בעדיפות גבוהה, אבל יש תור של משימות אחרות, הדפדפן בדרך כלל ימשיך את המסגרת הנוכחית הרבה אחרי 16.66 אלפיות השנייה, לא משנה כמה טוב החלוקה של המשימות בתוכה. כלומר, הדפדפן תמיד ינסה לתת עדיפות לקלטים, אבל יכול להיות שהוא יבחר לטפל בתור של משימות במקום בעדכוני רינדור. הסיבה לכך היא שרינדור הוא תהליך יקר, ולכן עיבוד של משימת רינדור משולבת לכמה משימות בדרך כלל מוביל לירידה משמעותית בנפח העבודה הכולל.
לכן, פריים אנימציה ארוך עם ערך blockingDuration
נמוך או אפס עדיין אמור להגיב לגירויים. לכן, כדי לשפר את היכולת להגיב במהירות, כפי שמתבטאת במדד INP, חשוב לצמצם או לבטל את blockingDuration
על ידי פירוקה של משימות ארוכות.
עם זאת, הרבה פריימים ארוכים של אנימציה, ללא קשר ל-blockingDuration
, מצביעים על עדכוני ממשק משתמש שמתרחשים באיחור, ולכן עדיין יכולים להשפיע על רמת החלקות ולגרום לתחושה של ממשק משתמש עם השהיה בזמן גלילה או אנימציה, גם אם מדובר בבעיה פחות משמעותית מבחינת הרספונסיביות כפי שנמדדת על ידי INP. כדי להבין את הבעיות בתחום הזה, כדאי לעיין ב-duration
. עם זאת, קשה יותר לבצע אופטימיזציה לבעיות האלה כי אי אפשר לפתור אותן על ידי פיצול העבודה, אלא צריך לצמצם את העבודה.
תזמונים של פריימים
חותמות הזמן שצוינו קודם מאפשרות לפצל את הפריים הארוך של האנימציה לזמנים:
תזמון | החישוב |
---|---|
שעת ההתחלה | startTime |
שעת סיום | startTime + duration |
משך העבודה | renderStart ? renderStart - startTime : duration |
משך העיבוד | renderStart ? (startTime + duration) - renderStart: 0 |
רינדור: משך הזמן שלפני הפריסה | styleAndLayoutStart ? styleAndLayoutStart - renderStart : 0 |
רינדור: משך הזמן של סגנון ופריסה | styleAndLayoutStart ? (startTime + duration) - styleAndLayoutStart : 0 |
שיוך משופר של סקריפטים
סוג הרשומה long-animation-frame
כולל נתוני שיוך טובים יותר של כל סקריפט שתרם לפריים ארוך של אנימציה (במקרה של סקריפטים ארוכים מ-5 אלפיות השנייה).
בדומה ל-Long Tasks API, הנתונים האלה יסופקו במערך של רשומות שיוך, שבכל אחת מהן מפורטים:
- גם
name
וגםEntryType
יחזירו את הערךscript
. - ערך משמעותי של
invoker
, שמציין את אופן הקריאה לסקריפט (לדוגמה,'IMG#id.onload'
,'Window.requestAnimationFrame'
או'Response.json.then'
). - הערך של
invokerType
בנקודת הכניסה של הסקריפט:user-callback
: קריאה חוזרת ידועה שרשומה מ-API של פלטפורמת אינטרנט (לדוגמה,setTimeout
, requestAnimationFrame
).event-listener
: מאזין לאירוע בפלטפורמה (לדוגמה,click
, load
, keyup
).resolve-promise
: הטיפול בהבטחה של פלטפורמה (לדוגמה,fetch()
. הערה: במקרה של הבטחות, כל הטיפולים של אותן הבטחות מעורבבים יחד כ'סקריפט' אחד).
reject-promise
: כמו ב-resolve-promise
, אבל לגבי הדחייה.classic-script
: הערכת סקריפט (לדוגמה,<script>
אוimport()
)module-script
: זהה ל-classic-script
, אבל עבור סקריפטים של מודולים.
- נתוני תזמון נפרדים לסקריפט הזה:
startTime
: הזמן שבו הופעלה פונקציית הכניסה.duration
: משך הזמן שחלף ביןstartTime
לבין סיום העיבוד של תור המשימות הקטנות הבא.executionStart
: הזמן אחרי הידור.forcedStyleAndLayoutDuration
: משך הזמן הכולל של עיבוד הפריסה והסגנון המוגדרים מראש בתוך הפונקציה הזו (ראו טראשינג).pauseDuration
: משך הזמן הכולל של פעולות סנכרוניות 'בהשהיה' (התראה, XHR סינכרוני).
- פרטי מקור הסקריפט:
sourceURL
: שם משאב הסקריפט, אם הוא זמין (או ריק אם הוא לא נמצא).sourceFunctionName
: שם פונקציית הסקריפט, אם הוא זמין (או ריק אם הוא לא נמצא).sourceCharPosition
: המיקום של התו בסקריפט, אם הוא זמין (או -1 אם הוא לא נמצא).
windowAttribution
: מאגר הנתונים (המסמך ברמת העליונה או<iframe>
) שבו התרחשה מסגרת האנימציה הארוכה.window
: הפניה לחלון מאותו מקור.
כאשר הנתונים האלה זמינים, רשומות המקור מאפשרות למפתחים לדעת בדיוק איך כל סקריפט בפריים הארוך של האנימציה הופעל, עד למיקום התו בסקריפט הקריאה. כך אפשר למצוא את המיקום המדויק במשאב JavaScript שהוביל ליצירת הפריים הארוך של האנימציה.
דוגמה לרשומה של ביצועים ב-long-animation-frame
דוגמה מלאה של רשומת ביצועים מסוג long-animation-frame
, שמכילה סקריפט אחד, היא:
{
"blockingDuration": 0,
"duration": 60,
"entryType": "long-animation-frame",
"firstUIEventTimestamp": 11801.099999999627,
"name": "long-animation-frame",
"renderStart": 11858.800000000745,
"scripts": [
{
"duration": 45,
"entryType": "script",
"executionStart": 11803.199999999255,
"forcedStyleAndLayoutDuration": 0,
"invoker": "DOMWindow.onclick",
"invokerType": "event-listener",
"name": "script",
"pauseDuration": 0,
"sourceURL": "https://web.dev/js/index-ffde4443.js",
"sourceFunctionName": "myClickHandler",
"sourceCharPosition": 17796,
"startTime": 11803.199999999255,
"window": [Window object],
"windowAttribution": "self"
}
],
"startTime": 11802.400000000373,
"styleAndLayoutStart": 11858.800000000745
}
כפי שאפשר לראות, כך אפשר לקבל כמות נתונים חסרת תקדים לאתרים, כדי להבין מה גורם לזמן אחזור ארוך בעדכוני הרינדור.
שימוש ב-Long Animation Frames API בשדה
כלים כמו Chrome DevTools ו-Lighthouse שימושיים לזיהוי בעיות ולשחזור שלהן, אבל הם כלים לניסוי וטעייה שעשויים לפספס היבטים חשובים של חוויית המשתמש שרק נתוני שדה יכולים לספק.
Long Animation Frames API מיועד לשימוש בשטח כדי לאסוף נתוני הקשר חשובים של אינטראקציות של משתמשים, שלא ניתן היה לאסוף באמצעות Long Tasks API. כך תוכלו לזהות בעיות באינטראקטיביות ולשחזר אותן, וייתכן שלא הייתם מגלים אותן אחרת.
תמיכה ב-Long Animation Frames API לזיהוי תכונות
אפשר להשתמש בקוד הבא כדי לבדוק אם ה-API נתמך:
if (PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) {
// Monitor LoAFs
}
קישור לאינטראקציה הארוכה ביותר ב-INP
התרחיש לדוגמה הברור ביותר לשימוש ב-Long Animation Frames API הוא כדי לעזור באבחון ובפתרון בעיות של אינטראקציה לציור הבא (INP), וזו הייתה אחת מהסיבות העיקריות לכך שצוות Chrome פיתח את ה-API הזה. אינטראקציה ראשונית טובה היא אינטראקציה שבה כל התגובות מתקבלות תוך 200 אלפיות שנייה או פחות מרגע האינטראקציה ועד לציור הפריים. מאחר שממשק ה-API של פריימים ארוכים באנימציה מודד את כל הפריימים שנדרשות להם 50 אלפיות שנייה או יותר, רוב האינטראקציות הראשוניות הבעייתיות אמורות לכלול נתוני LoAF שיעזרו לכם לאבחן את האינטראקציות האלה.
'INP LoAF' הוא ה-LoAF שכולל את האינטראקציה מסוג INP, כפי שמוצג בתרשים הבא:
במקרים מסוימים, אירוע INP יכול לחול על שני פריימים של LoAF – בדרך כלל אם האינטראקציה מתרחשת אחרי שהפריים התחיל את חלק העיבוד של הפריים הקודם, ולכן עיבוד האירוע מתבצע בפריים הבא:
במקרים נדירים, יכול להיות שהיא תכלול יותר משני אירועי LoAF.
תיעוד הנתונים של LoAF שמשויכים לאינטראקציה עם INP מאפשר לכם לקבל מידע רב יותר על האינטראקציה עם INP כדי לעזור לכם לאבחן אותה. האפשרות הזו מועילה במיוחד להבנת עיכוב הקלט: אפשר לראות אילו סקריפטים אחרים הופעלו באותו פריים.
כדאי גם להבין את משך העיבוד ואת העיכוב בהצגה אם פונקציות הטיפול באירועים לא יוצרות את הערכים שמוצגים עבורם, כי יכול להיות שסקריפטים אחרים פועלים אצל המשתמשים שלכם ולא נכללים בבדיקות שלכם.
אין ממשק API ישיר שמאפשר לקשר רשומה ב-INP לרשומה או לרשומות הרלוונטיות ב-LoAF, אבל אפשר לעשות זאת בקוד על ידי השוואה בין זמני ההתחלה והסיום של כל אחת מהן (ראו את הסקריפט לדוגמה WhyNp). הספרייה web-vitals
כוללת את כל ה-LoAFs החופפים בנכס longAnimationFramesEntries
של ממשק השיוך של INP מגרסה 4.
אחרי שמקשרים את הרשומה או הרשומות של LoAF, אפשר לכלול מידע עם שיוך של INP. האובייקט scripts
מכיל חלק מהמידע החשוב ביותר, כי הוא יכול להראות מה עוד היה פועל בפריימים האלה. שליחת הנתונים האלה בחזרה לשירות הניתוח תאפשר לכם להבין טוב יותר למה האינטראקציות היו איטיות.
דיווח על אירועי LoAF עבור האינטראקציה עם INP היא דרך טובה למצוא את בעיות האינטראקטיביות הדחופות ביותר בדף. כל משתמש עשוי לקיים אינטראקציה שונה עם הדף שלכם, וכאשר יש מספיק נפח של נתוני שיוך של INP, מספר בעיות פוטנציאליות ייכללו בנתוני השיוך של INP. כך תוכלו למיין סקריפטים לפי נפח כדי לראות אילו סקריפטים קשורים ל-INP איטי.
דיווח על נתונים נוספים של אנימציות ארוכות לנקודת קצה לניתוח נתונים
אחד החסרונות של בדיקה של דיווחים על בעיות ב-INP בלבד הוא שיכול להיות שתחמיצו אזורים פוטנציאליים אחרים לשיפור שעשויים לגרום לבעיות INP בעתיד. המצב הזה עלול לגרום לתחושה של 'ריצה אחרי הזנב', שבה פותרים בעיה ב-INP ומצפים לשיפור משמעותי, רק כדי לגלות שהאינטראקציה האיטית הבאה טובה רק במעט מהאינטראקציה הקודמת, כך שה-INP לא משתפר הרבה.
לכן, במקום להסתכל רק על זמן הטעינה של INP, כדאי להביא בחשבון את כל זמני הטעינה במהלך משך החיים של הדף:
עם זאת, כל רשומה של LoAF מכילה כמות גדולה של נתונים, לכן סביר להניח שתרצו להגביל את הניתוח רק לחלק מה-LoAF. בנוסף, מכיוון שהרשומות של מסגרות האנימציה הארוכות יכולות להיות גדולות למדי, המפתחים צריכים להחליט אילו נתונים מהרשומה צריך לשלוח ל-Analytics. לדוגמה, זמני הסיכום של הרשומה ואולי שמות הסקריפטים, או קבוצה מינימלית אחרת של נתוני הקשר אחרים שעשויים להיחשב כנדרש.
דוגמאות לדפוסים שיכולים לעזור לצמצם את כמות הנתונים של פריימים ארוכים של אנימציה:
- הצגת פריים ארוכים של אנימציה עם אינטראקציות
- הצגת פריימים ארוכים של אנימציה עם משכי זמן חסימה ארוכים
- הצגת פריימים ארוכים של אנימציה במהלך עדכונים קריטיים של ממשק המשתמש כדי לשפר את רמת החלקות
- הצגת הפריים הארוכים ביותר של האנימציה
- זיהוי דפוסים נפוצים בפריימים ארוכים של אנימציה
איזה מהדפוסים האלה הכי מתאים לכם תלוי בשלב שבו אתם נמצאים בתהליך האופטימיזציה ובמידת הנפוצות של פריימים ארוכים באנימציה. באתר שלא בוצעה בו אופטימיזציה של תגובה מהירה בעבר, יכול להיות שיופיעו הרבה פריטים לא פעילים. לכן, מומלץ להגביל את הבדיקה רק לפריטים לא פעילים עם אינטראקציות, להגדיר ערך סף גבוה או לבדוק רק את הפריטים הגרועים ביותר.
כשתטפלו בבעיות הנפוצות שקשורות לתגובה מהירה, תוכלו להרחיב את האפשרות הזו על ידי אי-הגבלה רק על אינטראקציות או על משכי זמן חסימה ארוכים, או על ידי הנמכת ערכי הסף.
צפייה בפריימים ארוכים של אנימציה עם אינטראקציות
כדי לקבל תובנות מעבר לפריים האנימציה הארוך של INP, אפשר לבחון את כל הפריימים הארוכים של אנימציה עם אינטראקציות (שאפשר לזהות לפי נוכחות הערך firstUIEventTimestamp
) עם ערך blockingDuration
גבוה.
זו גם שיטה קלה יותר למעקב אחרי אירועי LoAF ב-INP, במקום לנסות למצוא מתאם בין השניים, שעשוי להיות מורכב יותר. ברוב המקרים, הנתונים האלה יכללו את זמן ה-LoAF של INP לביקור נתון. במקרים נדירים שבהם הנתונים האלה לא כוללים את זמן ה-LoAF של INP, עדיין יוצגו אינטראקציות ארוכות שחשוב לתקן, כי הן עשויות להיות האינטראקציה של INP אצל משתמשים אחרים.
הקוד הבא מתעד ביומן את כל הרשומות של LoAF עם blockingDuration
גדול מ-100 אלפיות השנייה, שבהן התרחשה אינטראקציה במהלך המסגרת. הערך 100 נבחר כאן כי הוא נמוך מסף ה-INP 'הטוב' של 200 אלפיות השנייה. אפשר לבחור ערך גבוה או נמוך יותר בהתאם לצרכים שלכם.
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.blockingDuration > REPORTING_THRESHOLD_MS &&
entry.firstUIEventTimestamp > 0
) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
מעקב אחרי פריימים ארוכים של אנימציה עם משכי זמן חסימה ארוכים
כדי לשפר את הניתוח של כל הפריימים הארוכים של האנימציה עם אינטראקציות, כדאי לבדוק את כל הפריימים הארוכים של האנימציה עם משכי זמן חסימה ארוכים. אלה מצביעים על בעיות פוטנציאליות ב-INP אם משתמש מבצע אינטראקציה במהלך הפריימים הארוכים של האנימציה.
הקוד הבא מתעד ביומן את כל הרשומות של LoAF עם משך חסימה של יותר מ-100 אלפיות שנייה, שבהן התרחשה אינטראקציה במהלך המסגרת. הערך 100 נבחר כאן כי הוא נמוך מסף ה-INP 'טוב' של 200 אלפיות השנייה, כדי לעזור לזהות פריימים בעייתיים פוטנציאליים, תוך צמצום כמות הפריימים הארוכים של האנימציה שמדווחים למינימום. אפשר לבחור ערך גבוה או נמוך יותר בהתאם לצרכים שלכם.
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
for (const entry of list.getEntries()) {
if (entry.blockingDuration > REPORTING_THRESHOLD_MS) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
כדאי לבדוק את מסגרות האנימציה הארוכות במהלך עדכונים קריטיים של ממשק המשתמש כדי לשפר את רמת החלקות
כפי שצוין קודם, כדאי לבדוק את משך החסימה הארוך של פריימים ארוכים של אנימציה כדי לטפל בזמן התגובה של הקלט. עם זאת, כדי שהאנימציה תהיה חלקה, צריך לבדוק את כל הפריימים הארוכים של האנימציה עם duration
ארוך.
מכיוון שהנתונים האלה יכולים להיות רועשים מאוד, מומלץ להגביל את המדידות שלהם לנקודות מפתח לפי דפוס כזה:
const REPORTING_THRESHOLD_MS = 100;
const observer = new PerformanceObserver(list => {
if (measureImportantUIupdate) {
for (const entry of list.getEntries()) {
if (entry.duration > REPORTING_THRESHOLD_MS) {
// Example here logs to console, but could also report back to analytics
console.log(entry);
}
}
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
async function doUIUpdatesWithMeasurements() {
measureImportantUIupdate = true;
await doUIUpdates();
measureImportantUIupdate = false;
}
איך בודקים את מסגרות האנימציה הארוכות הגרועות ביותר
במקום להגדיר סף, בעלי אתרים יכולים לאסוף נתונים על הפריים (או הפריים) הארוך ביותר של האנימציה, כדי לצמצם את נפח הנתונים שצריך לשלוח באמצעות איתות. לכן, לא משנה כמה פריימים ארוכים של אנימציה יש בדף, המערכת תשלח חזרה רק נתונים לגבי חמישה, עשרה או כמה פריימים ארוכים של אנימציה שהכי איטיים, או כמה שצריך.
MAX_LOAFS_TO_CONSIDER = 10;
let longestBlockingLoAFs = [];
const observer = new PerformanceObserver(list => {
longestBlockingLoAFs = longestBlockingLoAFs.concat(list.getEntries()).sort(
(a, b) => b.blockingDuration - a.blockingDuration
).slice(0, MAX_LOAFS_TO_CONSIDER);
});
observer.observe({ type: 'long-animation-frame', buffered: true });
אפשר גם לשלב בין השיטות האלה – לבדוק רק את 10 ה-LoAFs הגרועים ביותר, עם אינטראקציות שנמשכות יותר מ-100 אלפיות השנייה.
בזמן המתאים (רצוי באירוע visibilitychange
), האות חוזר ל-Analytics. אפשר להשתמש ב-console.table
מדי פעם כדי לבצע בדיקות מקומיות:
console.table(longestBlockingLoAFs);
זיהוי דפוסים נפוצים בפריימים ארוכים של אנימציה
אסטרטגיה חלופית היא לבדוק סקריפטים נפוצים שמופיעים הכי הרבה פעמים ברשומות של פריימים ארוכים של אנימציה. אפשר לדווח על נתונים ברמת הסקריפט וברמת מיקום התו כדי לזהות גורמים חוזרים.
האפשרות הזו מתאימה במיוחד לפלטפורמות שניתן להתאים אישית, שבהן אפשר לזהות נושאים או יישומי פלאגין שגורמים לבעיות בביצועים במספר אתרים.
אפשר לסכם את זמן הביצוע של סקריפטים נפוצים – או מקורות של צד שלישי – בפריימים ארוכים של אנימציה ולדווח על כך כדי לזהות גורמים נפוצים לפריימים ארוכים של אנימציה באתר או באוסף של אתרים. לדוגמה, כדי לבדוק כתובות URL:
const observer = new PerformanceObserver(list => {
const allScripts = list.getEntries().flatMap(entry => entry.scripts);
const scriptSource = [...new Set(allScripts.map(script => script.sourceURL))];
const scriptsBySource= scriptSource.map(sourceURL => ([sourceURL,
allScripts.filter(script => script.sourceURL === sourceURL)
]));
const processedScripts = scriptsBySource.map(([sourceURL, scripts]) => ({
sourceURL,
count: scripts.length,
totalDuration: scripts.reduce((subtotal, script) => subtotal + script.duration, 0)
}));
processedScripts.sort((a, b) => b.totalDuration - a.totalDuration);
// Example here logs to console, but could also report back to analytics
console.table(processedScripts);
});
observer.observe({type: 'long-animation-frame', buffered: true});
דוגמה לפלט הזה:
(index) |
sourceURL |
count |
totalDuration |
---|---|---|---|
0 |
'https://example.consent.com/consent.js' |
1 |
840 |
1 |
'https://example.com/js/analytics.js' |
7 |
628 |
2 |
'https://example.chatapp.com/web-chat.js' |
1 |
5 |
שימוש ב-Long Animation Frames API בכלים
ה-API מאפשר גם להשתמש בכלים נוספים למפתחים לניפוי באגים מקומי. כלי פיתוח מסוימים, כמו Lighthouse ו-Chrome DevTools, הצליחו לאסוף חלק גדול מהנתונים האלה באמצעות פרטי מעקב ברמה נמוכה יותר, אבל ה-API ברמה גבוהה יותר הזה עשוי לאפשר לכלים אחרים לגשת לנתונים האלה.
הצגת נתונים של פריימים של אנימציות ארוכות בכלי הפיתוח
אתם יכולים להציג ב-DevTools פריימים ארוכים של אנימציה באמצעות ה-API של performance.measure()
. לאחר מכן, הם יוצגו במעקב אחר זמני השימוש של המשתמשים ב-DevTools בנתוני המעקב אחר הביצועים, כדי להראות איפה כדאי להתמקד בשיפור הביצועים. באמצעות DevTools Extensibility API אפשר אפילו להציג אותם בטר'ק משלהם:
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
performance.measure('LoAF', {
start: entry.startTime,
end: entry.startTime + entry.duration,
detail: {
devtools: {
dataType: "track-entry",
track: "Long animation frames",
trackGroup: "Performance Timeline",
color: "tertiary-dark",
tooltipText: 'LoAF'
}
}
});
}
});
observer.observe({ type: 'long-animation-frame', buffered: true });
בטווח הארוך, סביר להניח שפריימים ארוכים של אנימציה ייכללו בכלי הפיתוח עצמו, אבל בינתיים קטע הקוד הקודם מאפשר להציג אותם שם.
הרשומה הראשונה בתרשים הקודם מראה גם איפה הדפדפן עיבד כמה משימות יחד באותו פריים ארוך של אנימציה, במקום לבצע רינדור בין המשימות. כפי שצוין קודם, המצב הזה יכול לקרות כשאין משימות קלט בעדיפות גבוהה, אבל יש תור של משימות. למשימה הארוכה הראשונה יש עדכוני רינדור שצריך להשלים (אחרת, מסגרת האנימציה הארוכה הנוכחית תתאפס אחריה, ותתחיל מסגרת חדשה עם המשימה הבאה). אבל במקום לבצע את הרינדור הזה באופן מיידי, הדפדפן עיבד מספר משימות נוספות, ורק אז ביצע את המשימה הארוכה של הרינדור וסיים את מסגרת האנימציה הארוכה. הדוגמה הזו ממחישה את התועלת שבבדיקת פריימים ארוכים של אנימציה ב-DevTools, במקום רק משימות ארוכות, כדי לזהות עיכובים ברינדור.
שימוש בנתוני פריימים ארוכים של אנימציה בכלים אחרים למפתחים
התוסף של מדדי הליבה לבדיקת חוויית המשתמש באתר הציג את הערך ביומן סיכום של פרטי ניפוי באגים כדי לאבחן בעיות בביצועים.
עכשיו מוצגים גם נתונים של פריימים ארוכים של אנימציה לכל קריאה חוזרת של INP וכל אינטראקציה:
שימוש בנתונים של פריימים ארוכים של אנימציה בכלים לבדיקות אוטומטיות
באופן דומה, כלי בדיקה אוטומטיים בצינורות עיבוד נתונים של CI/CD יכולים לחשוף פרטים על בעיות פוטנציאליות בביצועים על ידי מדידת פריימים ארוכים של אנימציה במהלך הפעלה של חבילות בדיקה שונות.
שאלות נפוצות
ריכזנו כאן כמה מהשאלות הנפוצות בנושא ה-API הזה:
למה לא פשוט להרחיב או לבצע איטרציה על Long Tasks API?
זוהי דרך חלופית לדיווח על מדידה דומה, אבל שונה בסופו של דבר, של בעיות פוטנציאליות בתגובה. חשוב לוודא שהאתרים שמסתמכים על Long Tasks API הקיים ימשיכו לפעול, כדי למנוע שיבושים בתרחישי לדוגמה קיימים.
יכול להיות ש-Long Tasks API ייהנה מחלק מהתכונות של LoAF (כמו מודל שיוך משופר), אבל אנחנו מאמינים שהתמקדות בפריימים במקום במשימות מציעה יתרונות רבים שמבדילים את ה-API הזה באופן מהותי מ-Long Tasks API הקיים.
למה אין לי רשומות של סקריפטים?
יכול להיות שהסיבה לכך היא שפריים האנימציה הארוך לא נגרם בגלל JavaScript, אלא בגלל עיבוד (רנדור) נרחב.
מצב כזה יכול לקרות גם כאשר פריים האנימציה הארוך נובע מ-JavaScript, אבל אי אפשר לספק את השיוך לסקריפט מסיבות פרטיות שונות כפי שצוין למעלה (בעיקר כי JavaScript לא בבעלות הדף).
למה יש לי רשומות של סקריפטים אבל אין לי פרטי מקור או שהם מוגבלים?
יכולות להיות לכך כמה סיבות, למשל אין מקור טוב שאפשר להפנות אליו.
גם פרטי הסקריפטים יוגבלו רק ל-sourceURL
(לא כולל הפניות אוטומטיות) עבור סקריפטים של no-cors cross-origin
, עם מחרוזת ריקה עבור sourceFunctionName
ו--1
עבור sourceCharPosition
. כדי לפתור את הבעיה, אפשר לאחזר את הסקריפטים האלה באמצעות CORS על ידי הוספת crossOrigin = "anonymous"
לקריאה <script>
.
לדוגמה, סקריפט ברירת המחדל של Google Tag Manager שצריך להוסיף לדף:
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXXXXXX');</script>
<!-- End Google Tag Manager -->
אפשר לשפר את הקוד ולהוסיף את j.crossOrigin = "anonymous"
כדי לאפשר לספק פרטי שיוך מלאים ל-GTM.
האם ה-API הזה יחליף את Long Tasks API?
אנחנו מאמינים ש-Long Animation Frames API הוא ממשק API טוב ומלא יותר למדידת משימות ארוכות, אבל בשלב הזה אין תוכניות להוצאה משימוש של Long Tasks API.
אנחנו מבקשים משוב
אפשר לשלוח משוב ברשימת הבעיות ב-GitHub, או לדווח על באגים בהטמעת ה-API ב-Chrome בכלי למעקב אחר בעיות ב-Chrome.
סיכום
Long Animation Frames API הוא ממשק API חדש ומלהיב עם יתרונות פוטנציאליים רבים על פני Long Tasks API הקודם.
הוא מתגלה ככלי מרכזי לטיפול בבעיות שקשורות למהירות התגובה, כפי שנמדדות על ידי INP. קשה לבצע אופטימיזציה של מדד INP, וממשק ה-API הזה הוא אחת הדרכים שבהן צוות Chrome מנסה לעזור למפתחים לזהות בעיות ולטפל בהן בקלות רבה יותר.
עם זאת, היקף ה-Long Animation Frames API חורג ממדד ה-INP, והוא יכול לעזור לזהות סיבות אחרות לעדכונים איטיים שעשויות להשפיע על רמת החלקות הכוללת של חוויית המשתמש באתר.