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