אופטימיזציה בזמן ההפעלה של JavaScript

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

רשת

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

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

זו יכולה להיות בעיה, כי סוג החיבור בפועל לרשת של המשתמש עשוי להיות לא 3G, ‏ 4G או Wi-Fi. אתם יכולים להיות מחוברים לרשת Wi-Fi בקפה, אבל להתחבר לנקודה לשיתוף אינטרנט (Hotspot) סלולרית במהירויות 2G.

אתם יכולים להפחית את עלות העברת הנתונים ברשת של JavaScript באמצעות:

  • שולחים רק את הקוד שהמשתמש צריך.
    • משתמשים בפיצול קוד כדי לפצל את ה-JavaScript לקטעים קריטיים ולא קריטיים. חבילות מודולים כמו webpack תומכות בחלוקת קוד.
    • טעינה איטית של קוד לא קריטי.
  • צמצום קוד
  • דחיסה
    • לכל הפחות, כדאי להשתמש ב-gzip כדי לדחוס משאבים מבוססי-טקסט.
    • מומלץ להשתמש ב-Brotli‏ ~q11. יחס הדחיסה של Brotli טוב יותר מזה של gzip. בעזרת הכלי, ב-CertSimple הצליחו לצמצם את גודל הבייטים של ה-JS המכווץ ב-17%, וב-LinkedIn הצליחו לצמצם את זמני הטעינה ב-4%.
  • הסרת קוד שלא בשימוש.
  • שמירת קוד במטמון כדי לצמצם את מספר הבקשות לרשת.
    • כדאי להשתמש באחסון במטמון של HTTP כדי לוודא שהדפדפנים מאחסנים את התשובות במטמון בצורה יעילה. כדי להימנע מהעברת בייטים שלא השתנו, כדאי לקבוע את משך החיים האופטימלי לסקריפטים (max-age) ולספק אסימוני אימות (ETag).
    • שימוש במטמון של קובץ שירות (service worker) יכול לשפר את עמידות הרשת של האפליקציה ולספק גישה מיידית לתכונות כמו מטמון הקוד של V8.
    • כדאי להשתמש במטמון לטווח ארוך כדי שלא תצטרכו לאחזר מחדש משאבים שלא השתנו. אם משתמשים ב-Webpack, אפשר לעיין במאמר גיבוב של שמות קבצים.

ניתוח/הידור

אחרי ההורדה, אחד מהעלויות הכבדות של JavaScript הוא הזמן שנדרש למנוע JS לנתח/לעבד את הקוד הזה. ב-Chrome DevTools, הניתוח וההדרכה הם חלק מהזמן הצהוב 'כתיבה ב-Script' בחלונית 'ביצועים'.

ALT_TEXT_HERE

בכרטיסיות 'מלמטה למעלה' ו'עץ קריאות' מוצגים זמני הניתוח/הקמפלקציה המדויקים:

ALT_TEXT_HERE
חלונית הביצועים של כלי הפיתוח ל-Chrome > מלמטה למעלה. כשמפעילים את נתוני הסטטיסטיקה של קריאות בסביבת זמן הריצה ב-V8, אפשר לראות את משך הזמן שבו חלפו שלבים כמו ניתוח ותכנות

אבל למה זה חשוב?

ALT_TEXT_HERE

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

עיבוד JavaScript בדפדפן יקר יותר מבייטים לכל תמונה או גופן אינטרנט בגודל שווה – Tom Dale

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

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

כשאנחנו מדברים על איטיות של ניתוח וקמפלקציה, חשוב להביא בחשבון את ההקשר – אנחנו מדברים כאן על טלפונים ניידים ממוצעים. משתמשים ממוצעים יכולים להשתמש בטלפונים עם מעבדים מרכזיים ומעבדי GPU איטיים, ללא מטמון L2/L3 ואולי אפילו עם מגבלת זיכרון.

יכולות הרשת והיכולות של המכשיר לא תמיד תואמות. משתמש עם חיבור Fiber מדהים לא בהכרח מקבל את המעבד הטוב ביותר לניתוח ולבדיקה של JavaScript שנשלח למכשיר שלו. זה נכון גם להפך… חיבור רשת גרוע אבל מעבד מהיר במיוחד. – Kristofer Baxter, LinkedIn

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

ALT_TEXT_HERE
בתרשים הזה מודגשים זמני הניתוח של חבילת JavaScript בגודל 1MB (כ-250KB בפורמט GZIP) במכשירים נייחים ובמכשירים ניידים מסוגים שונים. כשבודקים את העלות של הניתוח, צריך להביא בחשבון את הנתונים ללא דחיסה.לדוגמה, קוד JavaScript דחוס בגודל של כ-250KB יתבטל הדחיסה שלו ויהפוך לקוד בגודל של כ-1MB.

מה קורה אם מדובר באתר בעולם האמיתי, כמו CNN.com?

ב-iPhone 8 מתקדם, ניתוח או הידור של ה-JS של CNN נמשכים כ-4 שניות, לעומת כ-13 שניות בטלפון ממוצע (Moto G4). הדבר יכול להשפיע באופן משמעותי על המהירות שבה משתמש יכול ליצור אינטראקציה מלאה עם האתר.

ALT_TEXT_HERE
למעלה מוצגים זמני הניתוח של השוואת הביצועים של צ'יפ A11 Bionic של Apple ל-Snapdragon 617 בחומרה רגילה יותר של Android.

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

ALT_TEXT_HERE
מערכת Google Analytics יכולה לספק תובנות לגבי הסוגים של מכשירים ניידים שבאמצעותם המשתמשים האמיתיים ניגשים לאתר שלכם. כך תוכלו להבין את המגבלות האמיתיות של המעבדים המרכזיים (CPU) או של המעבדים הגרפיים (GPU) שבהם הם פועלים.

האם אנחנו באמת שולחים יותר מדי JavaScript? אולי :)

בעזרת HTTP Archive (כ-500,000 אתרים מובילים) כדי לנתח את המצב של JavaScript בניידים, אנחנו יכולים לראות של-50% מהאתרים נדרשות יותר מ-14 שניות כדי להפוך לאינטראקטיביים. האתרים האלה משקיעים עד 4 שניות רק בניתוח ובהידור של JS.

ALT_TEXT_HERE

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

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

זמן ביצוע

לא רק ניתוח וקומפילציה יכולים להיות יקרים. הפעלת JavaScript (הרצת קוד אחרי שהוא נותח או הופעל) היא אחת מהפעולות שצריכות להתרחש ב-thread הראשי. זמני ביצוע ארוכים יכולים גם להשפיע על המועד שבו משתמש יכול לבצע אינטראקציה עם האתר.

ALT_TEXT_HERE

אם הסקריפט פועל במשך יותר מ-50 אלפיות השנייה, הזמן עד לפעילות מלאה מתעכב בכל משך הזמן שנדרש להורדה, להדרכה ולביצוע של ה-JS – Alex Russell

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

עלויות אחרות

JavaScript יכול להשפיע על ביצועי הדף בדרכים נוספות:

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

דפוסים להפחתת עלות העברת JavaScript

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

PRPL

PRPL (Push, Render, Pre-cache, Lazy-load) הוא תבנית שמבצעת אופטימיזציה לאינטראקטיביות באמצעות פיצול קוד ושימוש נרחב במטמון:

ALT_TEXT_HERE

נציג לכם תמונה ויזואלית של ההשפעה האפשרית.

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

ALT_TEXT_HERE

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

אתחול פרוגרסיבי

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

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

גישה טובה יותר עשויה להיות Bootstrapping הדרגתי. שליחת דף עם פונקציונליות מינימלית (הדף מורכב רק מ-HTML/JS/CSS הנדרשים למסלול הנוכחי). ככל שמגיעים יותר משאבים, האפליקציה יכולה לטעון אותם באיטרציה ולפתוח תכונות נוספות.

ALT_TEXT_HERE
Progressive Bootstrapping מאת Paul Lewis

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

מסקנות

גודל ההעברה הוא קריטי לרשתות ברמה נמוכה. זמן הניתוח חשוב במכשירים עם מעבדים שמוגבלים ל-CPU. חשוב לשמור על ערכי ה-latency וה-throughput נמוכים.

צוותים שבחרו להשתמש בתקציבי ביצועים מחמירים הצליחו לצמצם את זמני ההעברה והניתוח/הקמפלור של JavaScript. מומלץ לקרוא את המאמר של Alex Russell בנושא Can You afford it?: תקציבי ביצועים באינטרנט בעולם האמיתי" לקבלת הנחיות לגבי תקציבים לנייד.

ALT_TEXT_HERE
כדאי לחשוב כמה 'מרחב ראש' ב-JS ההחלטות הארכיטקטוניות שלנו יכולות להשאיר לנו לצורך לוגיקה של האפליקציה.

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

מידע נוסף