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

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

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

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

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

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

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

איך להתייחס להשהיה לאחר קלט

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

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

איך לצמצם את השהיה לאחר קלט

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

להימנע ממכשירי טיימר חוזרים שמפעילים עבודה מוגזמת ב-thread הראשי

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

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

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

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

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

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

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

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

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

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

חשוב לשים לב לחפיפה בין אינטראקציות

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

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

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

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

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

סיכום

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

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