לעיתים קרובות, ה-JavaScript גורם לשינויים חזותיים. לפעמים בעזרת שינויים של סגנון באופן ישיר, ולפעמים מדובר בחישובים שיגרמו לשינויים חזותיים, כמו חיפוש או מיון של נתונים מסוימים. קובצי JavaScript שמתעכבים בצורה לא תקינה או שממושכים הרבה זמן הם סיבה נפוצה לבעיות בביצועים, וצריך לצמצם את ההשפעה שלהם ככל האפשר.
שינוי ה-DOM, באמצעות הוספה והסרה של רכיבים, שינוי מאפיינים, מחלקות או באמצעות אנימציה, יגרום כולם לחשב מחדש סגנונות של רכיבים, ובמקרים רבים גם לפרוס (או להזרים מחדש) את הדף או חלקים ממנו. התהליך הזה נקרא חישוב סגנון מחושב.
החלק הראשון של סגנונות המחשוב הוא ליצור קבוצה של סלקטורים תואמים, שהם בעצם הדפדפן שמזהה אילו סיווגים, מעין בוררים ומזהים חלים על כל רכיב נתון.
החלק השני בתהליך כולל הוצאת כל כללי הסגנון מהבוררים התואמים וזיהוי הסגנונות הסופיים של הרכיב.
סיכום
- איך הפחתת העלויות לחישוב סגנון יכולה לקצר את זמן האחזור של אינטראקציות.
- הסלקטורים עוזרים להפחית את המורכבות. כדאי להשתמש במתודולוגיה שמתמקדת בכיתה (לדוגמה, BEM).
- מצמצמים את מספר הרכיבים שבהם צריך לחשב את חישוב הסגנון.
הזמן לחישוב מחדש של הסגנון וזמן האחזור של האינטראקציה
Interaction to Next Paint (INP) הוא מדד ביצועים בסביבת זמן ריצה שמתמקד במשתמשים, שמעריך את רמת הרספונסיביות הכוללת של הדף לקלט של משתמשים. כשזמן האחזור של האינטראקציה מוערך על ידי המדד הזה, הוא מודד את משך הזמן מרגע האינטראקציה של המשתמש עם הדף ועד לציור של המסגרת הבאה שמציגה את העדכונים החזותיים התואמים שבוצעו בממשק המשתמש.
רכיב חשוב באינטראקציה הוא הזמן שחולף עד לציור של הפריים הבא. עבודת הרינדור שבוצעה לצורך הצגת המסגרת הבאה מורכבת מחלקים רבים, כולל חישוב של סגנונות הדפים שמתרחשים ממש לפני עבודת הפריסה, הצביעה וההרכב. המאמר הזה מתמקד רק בעלויות של חישוב סגנונות, אבל חשוב להדגיש שהפחתה של כל חלק משלב הרינדור שהיא מהותית לאינטראקציה, תצמצם את זמן האחזור הכולל – כולל חישוב הסגנון.
להפחית את המורכבות של הבוררים
במקרה הפשוט ביותר, אתם יכולים להפנות לרכיב ב-CSS שלכם באמצעות מחלקה בלבד:
.title {
/* styles */
}
עם זאת, ככל שהפרויקט יגדל, סביר להניח שהדבר יגרום ליצירת CSS מורכב יותר, וכתוצאה מכך עשויים להופיע סלקטורים שנראים כך:
.box:nth-last-child(-n+1) .title {
/* styles */
}
כדי לדעת איך הסגנונות האלה חלים על הדף, הדפדפן צריך לשאול את השאלה "האם זהו רכיב עם מחלקה של title
, שיש לו הורה שהוא במקרה צאצא nth ועוד רכיב אחד עם מחלקה של box
?". כדי להבין זאת, יכול להיות שייקח הרבה זמן, בהתאם לבורר שבו נעשה שימוש וגם לדפדפן הרלוונטי. במקום זאת, אפשר לשנות את ההתנהגות הרצויה של הבורר למחלקה:
.final-box-title {
/* styles */
}
יכול להיות שקיימת בעיה עם שם הכיתה, אבל המשימה נעשתה הרבה יותר קלה עבור הדפדפן. בגרסה הקודמת, כדי לדעת, למשל, שהאלמנט הוא האחרון מסוגו, הדפדפן צריך לדעת קודם הכול על כל הרכיבים האחרים, ואם יש רכיבים שמופיעים אחריו, הם יהיו ה-nth-last-child
, שהוא אולי יקר יותר מהתאמה של הבורר לאלמנט בגלל שהמחלקה שלו תואמת.
הפחתת מספר הרכיבים בסגנון
שיקול נוסף לגבי הביצועים – שבדרך כלל הוא הגורם החשוב יותר בעדכוני סגנון רבים – הוא הנפח העצום של העבודה שצריך לבצע כשרכיב מסוים משתנה.
באופן כללי, העלות הגרועה ביותר של חישוב סגנון הרכיבים המחושב היא מספר הרכיבים כפול מספר הבורר, מפני שצריך לבדוק כל רכיב לפחות פעם אחת מול כל סגנון כדי לראות אם הוא תואם.
לעיתים קרובות ניתן לטרגט חישובי סגנון ישירות לכמה רכיבים במקום לבטל את התוקף של הדף כולו. בדפדפנים מודרניים, הבעיה פחות משמעותית כי הדפדפן לא חייב לבדוק את כל הרכיבים שעשויים להיות מושפעים משינוי כלשהו. מצד שני, דפדפנים ישנים יותר לא בהכרח מותאמים בצורה אופטימלית למשימות כאלה. במקרים שבהם אפשר לעשות זאת, צריך לצמצם את מספר הרכיבים שלא תקפים.
מדידת העלות של חישוב מחדש של סגנון
אחת מהדרכים למדוד את העלות של חישובי מחדש של סגנונות היא להשתמש בחלונית הביצועים בכלי הפיתוח ל-Chrome. כדי להתחיל, פותחים את כלי הפיתוח, עוברים לכרטיסייה ביצועים, לוחצים על 'הקלטה' ומבצעים פעולות בדף. כשתפסיקו את ההקלטה, תראו משהו כזה בתמונה למטה:
הפס שלמעלה הוא תרשים להבות מיניאטוריות שמתווה גם פריימים בשנייה. ככל שהפעילות קרובה יותר לתחתית הרצועה, כך הדפדפן יצייר פריימים מהירים יותר. אם אתם רואים את תרשים הלהבות מתייצב למעלה עם פסים אדומים מעליו, סימן שיש עבודה שגורמת לפריימים ארוכים.
אם יש לכם מסגרת ממושכת במהלך אינטראקציה כמו גלילה, יש עליה בדיקה קפדנית יותר. אם יש לכם בלוק סגול גדול, מגדילים את התצוגה ובוחרים יצירה עם התווית חישוב מחדש של הסגנון כדי לקבל מידע נוסף על חישוב מחדש של סגנונות שעשויים להיות יקרים.
במשחק הזה יש תהליך ממושך של חישוב מחדש שנמשך קצת יותר מ-25 אלפיות השנייה.
אם תלחצו על האירוע עצמו, תוצג לכם מקבץ שיחות. אם עבודת העיבוד נובעת מאינטראקציה של משתמש, המקום ב-JavaScript שאחראי להפעלת שינוי הסגנון ייקרא. בנוסף לכך, יוצג לכם גם מספר הרכיבים שהושפעו מהשינוי - מעט יותר מ-900 רכיבים במקרה הזה - וכמה זמן נדרש לבצע את חישוב הסגנון. אפשר להשתמש במידע הזה כדי לנסות למצוא תיקון בקוד.
שימוש בבלוק, Element, משנה
שיטות תכנות כמו BEM (בלוק, Element, Modifier) מוטמעות למעשה בבורר היתרונות התואמים של הביצועים שהוזכרו קודם, מאחר שהשיטה המומלצת היא שלכל דבר תהיה מחלקה אחת, ובמקרים שבהם יש צורך בהיררכיה, גם בתוך שם הכיתה:
.list {
/* Styles */
}
.list__list-item {
/* Styles */
}
אם אתם צריכים להוסיף רכיב התאמה, כמו בדוגמה למעלה שבה אנחנו רוצים להוסיף פעולה מיוחדת לילד או לילדה האחרון, תוכלו להוסיף את הפקודה הבאה:
.list__list-item--last-child {
/* Styles */
}
אם אתם מחפשים דרך טובה לארגן את שירות ה-CSS שלכם, BEM הוא נקודת התחלה טובה, גם מנקודת מבט של מבנה, וגם מאחר שקל יותר לחפש סגנון שהמתודולוגיה מקדמת.
אם אתם לא אוהבים BEM, יש עוד דרכים לגשת לשירות ה-CSS, אבל כדאי להעריך את שיקולי הביצועים לצד הארגונומיה של הגישה.
משאבים
תמונה ראשית (Hero) מ-UnFlood, מאת Markus Spiske.