איך ולמה יצרנו את התובנות לגבי הביצועים

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

ALT_TEXT_HERE

למה ליצור לוח נוסף?

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

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

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

הקישור למשוב בחלונית

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

איך פיתחנו את התכונה 'תובנות לגבי הביצועים'

בדומה לשאר הכלים של DevTools, פיתחנו את Performance Insights ב-TypeScript והשתמשנו ברכיבי אינטרנט, עם תמיכה ב-lit-html, כדי ליצור את ממשק המשתמש. ההבדל בין 'תובנות לגבי ביצועים' לבין 'תובנות לגבי מודעות' הוא שממשק המשתמש הראשי הוא רכיב HTML‏ canvas, וציר הזמן מצויר על גבי הלוח הזה. חלק גדול מהמורכבות נובע מהניהול של הלוח: לא רק ציור הפרטים הנכונים במקום הנכון, אלא גם ניהול אירועי העכבר (לדוגמה: איפה המשתמש לחץ על הלוח? האם הם לחצו על אירוע שציירנו?) ולוודא שאנחנו מבצעים עיבוד מחדש של הלוח בצורה יעילה.

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

באתר נתון יש כמה 'טראקים' שאנחנו רוצים ליצור מהם רינדור, וכל אחד מהם מייצג קטגוריה אחרת של נתונים. לדוגמה, בחלונית התובנות יוצגו כברירת מחדל שלושה טראקים:

ככל שנוסיף תכונות לחלונית, נוסיף גם טראקים נוספים.

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

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

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

canvasContext.beginPath();
canvasContext.rect(
    trackVisibleWindow.x, trackVisibleWindow.y, trackVisibleWindow.width, trackVisibleWindow.height);
canvasContext.clip();

בנוסף, לא רצינו שכל טראק יצטרך לדעת מה המיקום שלו אנכית: כל טראק צריך להירנדר בעצמו כאילו הוא נרנדר ב-(0, 0), ויש לנו רכיב ברמה גבוהה יותר (שנקרא TrackManager) שמנהל את המיקום הכולל של הטראק. אפשר לעשות זאת באמצעות translate, שמעבירה את הלוח למיקום (x, y) נתון. לדוגמה:

canvasContext.translate(0, 10); // Translate by 10px in the y direction
canvasContext.rect(0, 0, 10, 10); // draw a rectangle at (0, 0) that’s 10px high and wide

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

קנבסים מחוץ למסך לטראקים ולרגעים מיוחדים

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

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

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

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

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

ניתוח מעקב (trace) שנבדק באופן מקיף

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

לנתח את קובץ המעקב ולשלוף את הנתונים הנדרשים. עיבוד של קבוצת טראקים.

הפרדת הניתוח (חלק 1) מהעבודה על ממשק המשתמש (חלק 2) אפשרה לנו ליצור מערכת ניתוח מוצקה. כל ניתוח עובר דרך סדרה של Handler (מנהלי אירועים) שאחראים על תחומים שונים: LayoutShiftHandler מחשב את כל המידע שאנחנו צריכים לזיהוי שינויים בפריסה, ו-NetworkRequestsHandler מטפל באופן בלעדי בחילוץ של בקשות רשת. גם שלב הניתוח המפורש הזה, שבו יש לנו מנהלים שונים שאחראים על חלקים שונים של המעקב, היה שימושי: ניתוח המעקב יכול להיות מורכב מאוד, וקל יותר להתמקד בבעיה אחת בכל פעם.

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

בדיקת צילומי מסך של ממשק המשתמש בקנבס

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

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

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

סיכום

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

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

הורדת הערוצים לתצוגה מקדימה

מומלץ להשתמש ב-Chrome Canary, ב-Dev או ב-Beta כדפדפן הפיתוח שמוגדר כברירת מחדל. ערוצי התצוגה המקדימה האלה מעניקים לכם גישה לתכונות העדכניות ביותר של DevTools, מאפשרים לכם לבדוק ממשקי API מתקדמים לפלטפורמות אינטרנט ולמצוא בעיות באתר לפני שהמשתמשים שלכם יעשו זאת.

יצירת קשר עם צוות כלי הפיתוח ל-Chrome

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