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