איך מבצעים אופטימיזציה של זמן האינטראקציה עד התוכן הבא באתר
תאריך פרסום: 19 במאי 2023, תאריך עדכון אחרון: 3 ביוני 2025
מהירות התגובה לאינטראקציה באתר (INP) הוא מדד יציב של המדדים הבסיסיים של חוויית המשתמש (Core Web Vitals) שמאפשר להעריך את רמת הרספונסיביות הכוללת של דף לאינטראקציות של משתמשים, על סמך משך זמן האחזור של כל האינטראקציות שעומדות בדרישות שמתרחשות בכל משך החיים של ביקור משתמש בדף. ערך ה-INP הסופי הוא משך הזמן הארוך ביותר של אינטראקציה שזוהה (לפעמים ללא חריגים חשודים בטעות).
כדי לספק חוויית משתמש טובה, אתרים צריכים לשאוף להגיע לזמן של 200 אלפיות השנייה או פחות מהאינטראקציה ועד לציור הבא. כדי לעמוד ביעד הזה עבור רוב המשתמשים, סף טוב למדידה הוא הפריסנטיל ה-75 של טעינת הדפים, שמפולח לפי מכשירים ניידים ומחשבים.
בהתאם לאתר, יכול להיות שיהיה מעט אינטראקציות או שאין אינטראקציות בכלל – למשל, דפים שכוללים בעיקר טקסט ותמונות עם מעט אלמנטים אינטראקטיביים או ללא אלמנטים כאלה. לחלופין, באתרים כמו כלי לעריכת טקסט או משחקים, יכולות להיות מאות ואפילו אלפי אינטראקציות. בכל מקרה שבו יש INP גבוה, חוויית המשתמש נמצאת בסיכון.
שיפור מדד INP דורש זמן ומאמץ, אבל התוצאה היא חוויית משתמש טובה יותר. במדריך הזה נסביר איך לשפר את INP.
איך בודקים מה גורם ל-INP נמוך
כדי לפתור בעיות של אינטראקציות איטיות, צריך נתונים שיאפשרו לכם לדעת אם מדד ה-INP של האתר שלכם נמוך או שצריך לשפר אותו. אחרי שתקבלו את המידע הזה, תוכלו לעבור למעבדה כדי להתחיל לאבחן אינטראקציות איטיות ולהגיע לפתרון.
איתור אינטראקציות איטיות בשטח
באופן אידיאלי, תהליך האופטימיזציה של מודעות ה-INP יתחיל בנתוני שדה. במקרה הטוב, נתוני שדה מספק של מעקב אחר משתמשים אמיתיים (RUM) יספקו לכם לא רק את ערך ה-INP של הדף, אלא גם נתונים לפי הקשר שמציינים איזו אינטראקציה ספציפית אחראית לערך ה-INP עצמו, אם האינטראקציה התרחשה במהלך טעינת הדף או אחריה, סוג האינטראקציה (קליק, הקשה על מקש או הקשה) ומידע חשוב נוסף.
אם אתם לא מסתמכים על ספק RUM כדי לקבל נתוני שטח, במדריך לנתוני שטח ב-INP מומלץ להשתמש ב-PageSpeed Insights כדי להציג את הנתונים מהדוח לגבי חוויית המשתמש ב-Chrome (CrUX) כדי למלא את הפערים. CrUX הוא מערך הנתונים הרשמי של תוכנית המדדים הבסיסיים של חוויית המשתמש (Core Web Vitals), והוא מספק סיכום ברמה גבוהה של מדדים לגבי מיליוני אתרים, כולל INP. עם זאת, בדרך כלל CrUX לא מספק את נתוני ההקשר שאתם מקבלים מספק RUM כדי לעזור לכם לנתח בעיות. לכן, אנחנו עדיין ממליצים לאתרים להשתמש בספק RUM כשהדבר אפשרי, או להטמיע פתרון RUM משלהם כדי להשלים את מה שזמין ב-CrUX.
אבחון אינטראקציות איטיות במעבדה
מומלץ להתחיל את הבדיקות ב-Labs אחרי שיש לכם נתונים מהשטח שמצביעים על אינטראקציות איטיות. אם אין נתונים מהשטח, יש כמה אסטרטגיות לזיהוי אינטראקציות איטיות במעבדה. אסטרטגיות כאלה כוללות מעקב אחרי תהליכי שימוש נפוצים ובדיקת אינטראקציות לאורך הדרך, וגם אינטראקציה עם הדף במהלך הטעינה – כשהפעילות בשרשור הראשי היא לרוב הכי ערה – כדי לזהות אינטראקציות איטיות במהלך החלק הזה, הקריטי, בחוויית המשתמש.
אופטימיזציה של האינטראקציות
אחרי שמזהים אינטראקציה איטית ואפשר לשחזר אותה באופן ידני בסביבת ה-Lab, השלב הבא הוא לבצע אופטימיזציה שלה. אפשר לפצל את האינטראקציות לשלושה חלקים משניים:
- הזמן שחלף מהקלט, שמתחיל כשהמשתמש מתחיל אינטראקציה עם הדף ומסתיים כשהקריאות החוזרות (callbacks) של האירוע לאינטראקציה מתחילות לפעול.
- משך העיבוד, שמורכב מהזמן שלוקח להשלמת קריאות החזרה (callbacks) של האירועים.
- הזמן שחולף מהצגת הבקשה ועד להצגת התוצאה, שהוא הזמן שחולף מהרגע שבו הדפדפן שולח את הבקשה ועד שהוא מציג את התוצאה החזותית של האינטראקציה.
סכום של שלושת החלקים האלה הוא זמן האחזור הכולל של האינטראקציה. כל חלק קטן באינטראקציה תורם זמן מסוים לזמן האחזור הכולל של האינטראקציה, ולכן חשוב לדעת איך לבצע אופטימיזציה של כל חלק באינטראקציה כדי שהיא תימשך זמן קצר ככל האפשר.
זיהוי והפחתה של השהיה לאחר קלט
כשמשתמש יוצר אינטראקציה עם דף, החלק הראשון של האינטראקציה הזו הוא השהיית הקלט. בהתאם לפעילות אחרת בדף, עיכובי הקלט יכולים להיות ארוכים. הסיבה לכך יכולה להיות פעילות שמתרחשת ב-thread הראשי (אולי בגלל טעינת סקריפטים, ניתוח וקמפלור שלהם), טיפול באחזור, פונקציות של טיימר או אפילו אינטראקציות אחרות שמתרחשות ברצף מהיר וחופפות זו לזו.
לא משנה מה המקור של עיכוב הקלט של אינטראקציה, מומלץ לצמצם את עיכוב הקלט למינימום כדי שהאינטראקציות יוכלו להתחיל להריץ קריאות חזרה (callbacks) של אירועים בהקדם האפשרי.
הקשר בין הערכת הסקריפט לבין משימות ארוכות במהלך ההפעלה
אחד מהיבטים קריטיים של האינטראקטיביות במחזור החיים של הדף הוא בזמן ההפעלה. כשדף נטען, הוא עובר עיבוד ראשוני, אבל חשוב לזכור שעיבוד של דף לא מעיד על סיום הטעינה שלו. בהתאם למספר המשאבים הדרושים לדף כדי שיהיה פעיל במלואו, יכול להיות שמשתמשים ינסו לבצע אינטראקציה עם הדף בזמן שהוא עדיין נטען.
אחת מהסיבות שיכולות להאריך את עיכוב הקלט של אינטראקציה בזמן טעינת דף היא הערכת סקריפט. אחרי שמאחזרים קובץ JavaScript מהרשת, עדיין יש לדפדפן עבודה לעשות לפני שאפשר להריץ את ה-JavaScript. העבודה הזו כוללת ניתוח סקריפט כדי לבדוק שהסינטקס שלו תקין, הידור שלו לקוד בייט ואז בסופו של דבר ביצוע שלו.
בהתאם לגודל הסקריפט, הפעולה הזו עלולה להוסיף משימות ארוכות לשרשור הראשי, וכתוצאה מכך הדפדפן יתעכב בתגובה לאינטראקציות אחרות של משתמשים. כדי שהדף ימשיך להגיב לקלט של המשתמש במהלך טעינת הדף, חשוב להבין מה אפשר לעשות כדי לצמצם את הסבירות לפעולות ארוכות במהלך טעינת הדף, וכך לשמור על מהירות הדף.
אופטימיזציה של קריאות חוזרות (callbacks) של אירועים
השהיה לאחר קלט היא רק החלק הראשון של המדד INP. בנוסף, צריך לוודא שהקריאות החוזרות (callbacks) של האירועים שפועלות בתגובה לאינטראקציה של משתמש יכולות להסתיים מהר ככל האפשר.
להעביר את הבעלות לשרשור הראשי לעיתים קרובות
העצה הכללית הטובה ביותר לביצוע אופטימיזציה של קריאות חזרה (callbacks) של אירועים היא לבצע בהן כמה שפחות עבודה. עם זאת, לוגיקת האינטראקציה עשויה להיות מורכבת, ויכול להיות שתוכלו לצמצם את העבודה שהן מבצעות רק במידה קטנה.
אם גיליתם שהמצב הזה קיים באתר שלכם, הדבר הבא שתוכלו לנסות הוא לפצל את העבודה באירועים חזרה (callbacks) למשימות נפרדות. כך העבודה המשותפת לא הופכת למשימה ארוכה שגורמת לחסימה של ה-thread הראשי, ומאפשרת לבצע אינטראקציות אחרות שבלעדיהן הן היו צריכות להמתין ל-thread הראשי.
setTimeout
היא אחת הדרכים לפצל משימות, כי פונקציית ה-callback שהועברה אליה פועלת במשימה חדשה. אפשר להשתמש ב-setTimeout
בפני עצמה או להעביר את השימוש בה לפונקציה נפרדת כדי לקבל תוצאות ארגונומיות יותר.
העברה ללא הבחנה היא טובה יותר מאשר לא להעביר בכלל – עם זאת, יש דרך מורכבת יותר להעביר את השליטה לשרשור הראשי, והיא כוללת העברה רק מיד אחרי קריאה חוזרת (callback) של אירוע שמעדכנת את ממשק המשתמש, כדי שהלוגיקה של הרינדור תוכל לפעול מוקדם יותר.
מניעת עיבוד כדי לאפשר לעיבוד להתבצע מוקדם יותר
שיטה מתקדמת יותר של העברת בקרה כוללת בניית מבנה לקוד בקריאות החזרה (callbacks) של האירועים, כדי להגביל את מה שיופעל רק ללוגיקה הנדרשת כדי להחיל עדכונים חזותיים על המסגרת הבאה. את כל שאר הדברים אפשר לדחות למשימה הבאה. כך לא רק שהקריאות החוזרות יהיו קלות וגמישות, אלא גם זמן הרינדור של האינטראקציות ישתפר, כי לא תתאפשר חסימה של קוד הקריאה החוזרת של האירוע על ידי עדכונים חזותיים.
לדוגמה, נניח שיש כלי לעריכת טקסט עשיר שמעצב את הטקסט בזמן ההקלדה, אבל גם מעדכן היבטים אחרים בממשק המשתמש בתגובה למה שכתבתם (כמו מספר המילים, הדגשת שגיאות איות ומשוב חזותי חשוב אחר). בנוסף, יכול להיות שהאפליקציה תצטרך לשמור את מה שכתבתם כדי שאם תצאו ותחזרו, לא תאבדו את העבודה.
בדוגמה הזו, ארבעת הדברים הבאים צריכים לקרות בתגובה לתווים שהמשתמש הקליד. עם זאת, רק הפריט הראשון צריך להתבצע לפני הצגת הפריים הבא.
- מעדכנים את תיבת הטקסט במה שהמשתמש הקליד ומחילים את העיצוב הנדרש.
- מעדכנים את החלק בממשק המשתמש שבו מוצג מספר המילים הנוכחי.
- מריצים לוגיקה כדי לבדוק אם יש שגיאות איות.
- שומרים את השינויים האחרונים (מקומית או במסד נתונים מרוחק).
הקוד שצריך להזין כדי לעשות זאת עשוי להיראות כך:
textBox.addEventListener('input', (inputEvent) => {
// Update the UI immediately, so the changes the user made
// are visible as soon as the next frame is presented.
updateTextBox(inputEvent);
// Use `setTimeout` to defer all other work until at least the next
// frame by queuing a task in a `requestAnimationFrame()` callback.
requestAnimationFrame(() => {
setTimeout(() => {
const text = textBox.textContent;
updateWordCount(text);
checkSpelling(text);
saveChanges(text);
}, 0);
});
});
בתרשים ההמחשה הבא אפשר לראות איך דחיית עדכונים לא קריטיים עד אחרי המסגרת הבאה יכולה לקצר את משך העיבוד, וכך את זמן האחזור הכולל של האינטראקציה.

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

עיבוד יתר של פריסה הוא צוואר בקבוק בביצועים, כי כשמעדכנים סגנונות ומבקשים מיד את הערכים של הסגנונות האלה ב-JavaScript, הדפדפן נאלץ לבצע עבודה סינכרנית של פריסה, שבמקרה אחר הוא היה יכול להמתין כדי לבצע אותה באופן אסינכררוני מאוחר יותר, אחרי שהפעלת ה-callbacks של האירועים תסתיים.
צמצום ההשהיה בהצגת התגובה
העיכוב בהצגה של סימנים של אינטראקציה נמשך מהרגע שבו פונקציות ה-call back של האירועים של האינטראקציה מסתיימות לפעול, ועד לנקודה שבה הדפדפן יכול לצייר את המסגרת הבאה שמוצגים בה השינויים החזותיים.
צמצום גודל DOM
כשה-DOM של דף קטן, עיבוד הגרפיקה בדרך כלל מסתיים במהירות. עם זאת, כשה-DOMs גדלים מאוד, עבודת הרינדור נוטה להתאים את עצמה לגודל ה-DOM. הקשר בין עבודת הרינדור לבין גודל ה-DOM הוא לא לינארי, אבל יצירת רינדור של DOM גדולים דורשת יותר עבודה מאשר יצירת רינדור של DOM קטנים. DOM גדול הוא בעייתי בשני מקרים:
- במהלך העיבוד הראשוני של הדף, שבו DOM גדול דורש הרבה עבודה כדי לעבד את המצב הראשוני של הדף.
- בתגובה לאינטראקציה של משתמש, שבה DOM גדול עלול לגרום לעדכוני רינדור יקרים מאוד, וכתוצאה מכך להאריך את הזמן הדרוש לדפדפן להציג את המסגרת הבאה.
חשוב לזכור שיש מקרים שבהם אי אפשר לצמצם באופן משמעותי DOM גדול. יש כמה גישות שאפשר להשתמש בהן כדי לצמצם את גודל ה-DOM, כמו פישטות ה-DOM או הוספה ל-DOM במהלך אינטראקציות של משתמשים כדי לשמור על גודל ה-DOM הראשוני קטן, אבל יכול להיות שהשיטות האלה לא יעזרו לכם להפחית את הגודל בצורה משמעותית.
שימוש ב-content-visibility
כדי ליצור עיבוד גרפי (render) בזמנם של רכיבים מחוץ למסך
אחת הדרכים להגביל את כמות העבודה של העיבוד במהלך טעינת הדף ואת כמות העבודה של העיבוד בתגובה לאינטראקציות של משתמשים היא להסתמך על המאפיין content-visibility
ב-CSS, שמבצע עיבוד עצל של רכיבים כשהם מתקרבים למסך. יכול להיות שתצטרכו להתאמן קצת כדי להשתמש ב-content-visibility
בצורה יעילה, אבל כדאי לבדוק אם התוצאה היא זמן עיבוד קצר יותר שיכול לשפר את מדד INP של הדף.
חשוב לשים לב לעלות הביצועים כשמבצעים עיבוד (רנדור) של HTML באמצעות JavaScript
כשיש HTML, יש ניתוח HTML. אחרי שהדפדפן מסיים לנתח את ה-HTML ל-DOM, הוא צריך להחיל עליו סגנונות, לבצע חישובים של פריסה ולאחר מכן להציג את הפריסה הזו. זוהי עלות בלתי נמנעת, אבל איך מבצעים את העיבוד של ה-HTML חשוב.
כשהשרת שולח HTML, הוא מגיע לדפדפן כסטרימינג. העברה בזמן אמת (streaming) פירושה שתגובת ה-HTML מהשרת מגיעה בקטעים. הדפדפן מבצע אופטימיזציה של האופן שבו הוא מטפל בסטרימינג על ידי ניתוח מצטבר של קטעי הסטרימינג כשהם מגיעים, והצגה שלהם בייט אחרי בייט. זוהי אופטימיזציה של הביצועים, כי הדפדפן משחרר את הבעלות על המשאבים באופן משתמע, באופן תקופתי ואוטומטי במהלך טעינת הדף, והיא זמינה בחינם.
הביקור הראשון בכל אתר תמיד יכלול כמה כמות של HTML, אבל גישה נפוצה היא להתחיל עם קטע מינימלי של HTML, ולאחר מכן להשתמש ב-JavaScript כדי לאכלס את אזור התוכן. עדכונים נוספים של אזור התוכן הזה מתרחשים גם כתוצאה מאינטראקציות של משתמשים. המודל הזה נקרא בדרך כלל מודל אפליקציית דף יחיד (SPA). אחד החסרונות של התבנית הזו הוא שכאשר מבצעים עיבוד HTML באמצעות JavaScript בצד הלקוח, לא רק שצריך לשלם על עיבוד ה-JavaScript ליצירת ה-HTML, אלא גם שהדפדפן לא ייצור קוד חלופי עד שהוא יסיים לנתח את ה-HTML הזה ולעבד אותו.
עם זאת, חשוב לזכור שאפילו אתרים שאינם SPA יכללו כנראה כמות מסוימת של עיבוד HTML באמצעות JavaScript כתוצאה מאינטראקציות. בדרך כלל זה בסדר, כל עוד לא מבצעים עיבוד (רנדרינג) של כמויות גדולות של HTML בצד הלקוח, דבר שעלול לעכב את הצגת המסגרת הבאה. עם זאת, חשוב להבין את ההשלכות על הביצועים של הגישה הזו לעיבוד HTML בדפדפן, ואת האופן שבו היא יכולה להשפיע על תגובת האתר לקלט של משתמשים אם מעבדים הרבה HTML באמצעות JavaScript.
סיכום
שיפור ה-INP של האתר הוא תהליך שצריך לבצע כל כמה זמן. כשתתקנו אינטראקציה איטית בשדה, סביר להניח – במיוחד אם האתר שלכם מציע הרבה אינטראקטיביות – שתתחילו למצוא אינטראקציות איטיות אחרות, ותצטרכו לבצע אופטימיזציה גם שלהן.
המפתח לשיפור מדד INP הוא התמדה. עם הזמן, תוכלו לשפר את רמת הרספונסיביות של הדף עד שהמשתמשים יהיו מרוצים מחוויית השימוש שהם מקבלים. סביר להניח שגם כשאתם מפתחים תכונות חדשות למשתמשים, תצטרכו לעבור את אותו תהליך של אופטימיזציה של אינטראקציות ספציפיות להם. זה ידרוש זמן ומאמץ, אבל זה הזמן והמאמץ ששווה להשקיע.
התמונה הראשית (Hero) מ-Unsplash, מאת David Pisnoy ושונה בהתאם לרישיון Unsplash.