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

למדו מהו השהיה לאחר קלט (פלט), והכירו שיטות להפחתת ההשפעה שלו, כדי להגביר את האינטראקטיביות.

ג'רמי וגנר
ג'רמי וגנר

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

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

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

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

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

מה המשמעות של העיכוב לאחר קלט

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

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

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

איך לצמצם את העיכוב בקלט

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

סיכום

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

תמונה ראשית (Hero) מתוך Un מועברים, מאת Erik Mclean.