אופטימיזציה של השהיה לאחר קלט

כאן אפשר להבין מהו השהיה לאחר קלט וללמד שיטות להפחתת הזמן הזה, כדי לאפשר אינטראקטיביות מהירה יותר.

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

מהו השהיה לאחר קלט?

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

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

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

מה צריך לדעת על עיכוב קלט?

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

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

איך לצמצם את ההשהיה לפני הקלט

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

להימנע מטיימרים חוזרים שמפעילים הרבה עבודה בשרשור הראשי

יש שתי פונקציות טיימר נפוצות ב-JavaScript שיכולות לגרום לעיכוב בקלט: setTimeout ו-setInterval. ההבדל בין שתי השיטות הוא ש-setTimeout מתזמנת קריאה חוזרת (callback) שתרוץ אחרי פרק זמן מסוים. לעומת זאת, setInterval מתזמנת קריאה חוזרת (callback) שתרוץ כל n אלפיות השנייה באופן קבוע, או עד שהטיימר יופסק ב-clearInterval.

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

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

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

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

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

להימנע ממשימות ארוכות

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

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

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

היזהרו מאינטראקציות חופפות

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

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

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

  • כדאי לשקול עזיבה מהדף הראשון של ערכי קלט כדי להגביל את מספר הפעמים שקריאה חוזרת (callback) של אירוע מופעלת בפרק זמן נתון.
  • אפשר להשתמש בפונקציה AbortController כדי לבטל בקשות יוצאות של fetch, כדי שלא יהיה עומס ב-thread הראשי כדי לטפל בקריאות חוזרות של fetch. הערה: אפשר להשתמש במאפיין signal של מופע AbortController גם כדי לבטל אירועים.

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

סיכום

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

תמונה ראשית (Hero) מ-Unbounce, מאת Erik Mclean.