מהו עיכוב קלט ואיך אפשר לצמצם אותו כדי לשפר את האינטראקטיביות.
אינטראקציות באינטרנט הן דבר מורכב, ומתרחשת בהן פעילות מגוונת בדפדפן. אבל מה שמשותף לכולם הוא שקיימת השהיית קלט מסוימת לפני שהפונקציות להחזרת קריאה של האירועים מתחילות לפעול. במדריך הזה נסביר מהו עיכוב קלט ומה אפשר לעשות כדי לצמצם אותו, וכך להאיץ את האינטראקציות באתר שלכם.
מהי השהיה לאחר קלט?
השהיה לאחר קלט ראשוני היא משך הזמן שמתחיל ברגע שבו המשתמש יוצר אינטראקציה עם דף – כמו הקשה על המסך, לחיצה עם העכבר או הקשה על מקש – עד לרגע שבו מתחילות לפעול פונקציות הקריאה החוזרת (callback) של האירוע שקשור לאינטראקציה. כל אינטראקציה מתחילה עם עיכוב מסוים בקלט.
חלק מהעיכוב בקלט הוא בלתי נמנע: תמיד לוקח זמן מסוים למערכת ההפעלה לזהות אירוע קלט ולהעביר אותו לדפדפן. עם זאת, החלק הזה של עיכוב הקלט לרוב לא מורגש, ויש דברים אחרים שקורים בדף עצמו שיכולים לגרום לעיכובים ארוכים מספיק בקלט כדי ליצור בעיות.
איך חושבים על השהיה לאחר קלט
באופן כללי, כדאי שכל חלק באינטראקציה יהיה קצר ככל האפשר, כדי שהאתר שלכם יעמוד בסף ה'טוב' של מדד מהירות התגובה לאינטראקציה באתר (INP), ללא קשר למכשיר של המשתמש. שמירה על עיכוב קלט נמוך היא רק חלק אחד מהדרישות כדי לעמוד בסף.
לכן, כדאי לשאוף לזמן השהיה הקצר ביותר שאפשר כדי לעמוד בסף ה'טוב' של INP. עם זאת, חשוב לדעת שאי אפשר לצפות לביטול מוחלט של עיכובים בקלט. כל עוד אתם נמנעים מעומס יתר על התהליך הראשי בזמן שהמשתמשים מנסים ליצור אינטראקציה עם הדף, עיכוב הקלט צריך להיות נמוך מספיק כדי למנוע בעיות.
איך מצמצמים את השהיית הקלט
כמו שציינו קודם, אי אפשר להימנע לחלוטין מעיכוב בקלט, אבל מצד שני, אפשר להימנע מחלק מהעיכובים בקלט. כן. אם אתם נתקלים בעיכובים ארוכים בהזנת נתונים, כדאי לקחת בחשבון את הדברים הבאים.
מומלץ להימנע מטיימרים חוזרים שמפעילים עבודה מוגזמת ב-thread הראשי
יש שתי פונקציות נפוצות של טיימר ב-JavaScript שיכולות לתרום לעיכוב בקלט: setTimeout ו-setInterval. ההבדל בין שתי הפונקציות הוא ש-setTimeout מתזמנת קריאה חוזרת להפעלה אחרי פרק זמן מוגדר. לעומת זאת, הפונקציה setInterval מתזמנת קריאה חוזרת להפעלה כל n אלפיות השנייה ללא הגבלת זמן, או עד שהטיימר מופסק באמצעות clearInterval.
setTimeout לא בעייתית כשלעצמה – למעשה, היא יכולה לעזור להימנע ממשימות ארוכות. עם זאת, זה תלוי במועד שבו מתרחש פסק הזמן, ובשאלה אם המשתמש מנסה ליצור אינטראקציה עם הדף כשפונקציית הקריאה החוזרת של פסק הזמן פועלת.
בנוסף, אפשר להריץ את setTimeout בלולאה או באופן רקורסיבי, ואז הוא פועל יותר כמו setInterval, אבל עדיף לא לתזמן את האיטרציה הבאה עד שהקודמת תסתיים. למרות שהמשמעות היא שהלולאה תעבור לשרשור הראשי בכל פעם שמתבצעת קריאה ל-setTimeout, חשוב לוודא שהקריאה החוזרת לא תבצע עבודה מוגזמת.
setInterval מפעיל קריאה חוזרת במרווחים, ולכן סביר יותר שיפריע לאינטראקציות. הסיבה לכך היא שבניגוד למופע יחיד של קריאה ל-setTimeout, שהוא קריאה חוזרת חד-פעמית שעשויה להפריע לאינטראקציה של המשתמש, האופי החוזר של setInterval מגדיל את הסיכוי שהוא יפריע לאינטראקציה, וכך יגדיל את השהיית הקלט של האינטראקציה.
setInterval שמשפיעה על השהיית הקלט, כפי שמוצג בחלונית הביצועים של כלי הפיתוח ל-Chrome. העיכוב הנוסף בקלט גורם להפעלת קריאות חוזרות (callback) של האירוע לאינטראקציה מאוחר יותר ממה שהיה יכול לקרות אחרת.
אם הטיימרים מופיעים בקוד של צד ראשון, יש לכם שליטה בהם. כדאי להעריך אם אתם צריכים אותם, או לנסות לצמצם את העבודה בהם ככל האפשר. אבל טיימרים בסקריפטים של צד שלישי הם סיפור אחר. לרוב אין לכם שליטה על הפעולות שסקריפט של צד שלישי מבצע, ולכן כדי לתקן בעיות ביצועים בקוד של צד שלישי, צריך לעבוד עם בעלי עניין כדי לקבוע אם סקריפט מסוים של צד שלישי נחוץ. אם הוא נחוץ, צריך ליצור קשר עם ספק הסקריפט של הצד השלישי כדי לקבוע מה אפשר לעשות כדי לתקן בעיות ביצועים שהוא עלול לגרום באתר שלכם.
הימנעות ממשימות ארוכות
דרך אחת לצמצם עיכובים ארוכים בקלט היא להימנע ממשימות ארוכות. אם יש לכם עומס עבודה רב ב-thread הראשי שחוסם אותו במהלך אינטראקציות, זה יגרום לעיכוב בקלט לפני שהמשימות הארוכות יסתיימו.
בנוסף לצמצום כמות העבודה שאתם מבצעים במשימה – ומומלץ תמיד לשאוף לבצע כמה שפחות עבודה בשרשור הראשי – אתם יכולים לשפר את מהירות התגובה לקלט של המשתמשים על ידי פיצול משימות ארוכות.
הימנעות מחפיפה בין אינטראקציות
חלק מאתגר במיוחד באופטימיזציה של INP הוא אם יש לכם אינטראקציות שחופפות. חפיפה בין אינטראקציות מתרחשת כשמבצעים אינטראקציה עם רכיב מסוים, ואז מבצעים אינטראקציה נוספת עם הדף לפני שהאינטראקציה הראשונית הספיקה לעבד את הפריים הבא.
הסיבות לחפיפה בין מקורות האינטראקציות יכולות להיות פשוטות, למשל משתמשים שמבצעים הרבה אינטראקציות בפרק זמן קצר. זה יכול לקרות כשמשתמשים מקלידים בשדות של טופס, שבהם יכולות להתרחש הרבה אינטראקציות עם המקלדת בפרק זמן קצר מאוד. אם העבודה על אירוע מרכזי יקרה במיוחד – כמו במקרה הנפוץ של שדות להשלמה אוטומטית שבהם מתבצעות בקשות רשת לשרת קצה עורפי – יש לכם כמה אפשרויות:
- כדאי לשקול הסרת כפילויות של קלט כדי להגביל את מספר הפעמים שפונקציית הקריאה החוזרת של אירוע מופעלת בפרק זמן נתון.
- כדאי להשתמש ב-
AbortControllerכדי לבטל בקשות יוצאות שלfetch, כדי שה-thread הראשי לא יהיה עמוס מדי בטיפול בקריאות חוזרות שלfetch. הערה: אפשר להשתמש גם במאפייןsignalשל מופעAbortControllerכדי לבטל אירועים.
מקור נוסף לעיכוב בקלט בגלל אינטראקציות חופפות יכול להיות אנימציות יקרות. בפרט, אנימציות ב-JavaScript עשויות להפעיל הרבה קריאות של requestAnimationFrame, מה שעלול להפריע לאינטראקציות של המשתמשים. כדי לעקוף את הבעיה הזו, מומלץ להשתמש באנימציות CSS ככל האפשר כדי להימנע מהוספה לתור של פריימים של אנימציה שעלולים להיות יקרים. אבל אם עושים את זה, חשוב להימנע מאנימציות לא מורכבות כדי שהאנימציות יפעלו בעיקר ב-GPU ובשרשורי ה-compositor, ולא בשרשור הראשי.
סיכום
יכול להיות שעיכובים בקלט לא מייצגים את רוב הזמן שנדרש להפעלת האינטראקציות, אבל חשוב להבין שכל חלק באינטראקציה דורש פרק זמן מסוים שאפשר לקצר. אם זמן ההשהיה של הקלט ארוך, יש לכם הזדמנויות לקצר אותו. כדי להפחית את ההשהיה לאחר קלט ראשוני, וכך לשפר את האינטראקטיביות של האתר עבור המשתמשים, כדאי להימנע משימוש חוזר בפונקציות חוזרות של טיימר, לחלק משימות ארוכות ולהיזהר מחפיפה פוטנציאלית בין אינטראקציות.
תמונה ראשית (Hero) מ-Unsplash, מאת Erik Mclean.