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

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

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

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

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

סיכום

  • יש להימנע מ-setTimeout או setInterval עבור עדכונים חזותיים. צריך להשתמש תמיד ב- requestAnimationFrame.
  • העברת JavaScript ארוך טווח מה-thread הראשי אל Web Workers.
  • להשתמש במיקרו-משימות כדי לבצע שינויי DOM במספר מסגרות.
  • כדי להעריך את ההשפעה של JavaScript, אפשר להשתמש בציר הזמן של כלי הפיתוח ל-Chrome ובכלי לניתוח ביצועי JavaScript.

שימוש ב-requestAnimationFrame לשינויים חזותיים

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

/**
    * If run as a requestAnimationFrame callback, this
    * will be run at the start of the frame.
    */
function updateScreen(time) {
    // Make visual updates here.
}

requestAnimationFrame(updateScreen);

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

הפרמטר setTimeout גורם לדפדפן לפספס פריים.

למעשה, jQuery נהג להשתמש ב-setTimeout להתנהגות animate שלה. הערך השתנה לשימוש requestAnimationFrame בגרסה 3. אם משתמשים בגרסה ישנה יותר של jQuery, אפשר צריך לתקן אותו כדי להשתמש בפונקציה requestAnimationFrame, מומלץ מאוד לעשות זאת.

הפחתת המורכבות או שימוש ב-Web Workers

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

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

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

var dataSortWorker = new Worker("sort-worker.js");
dataSortWorker.postMesssage(dataToSort);

// The main thread is now free to continue working on other things...

dataSortWorker.addEventListener('message', function(evt) {
    var sortedData = evt.data;
    // Update data on screen...
});

לא כל העבודה מתאימה למודל הזה: ל-Web Worker אין גישת DOM. כשהעבודה צריכה להיות ב-thread הראשי, כדאי להשתמש בקיבוץ באצווה של משימות, שבהן מפלחים את המשימה הגדולה יותר למיקרו-משימות, שכל אחת מהן נמשכת לא יותר מכמה אלפיות השנייה, ופועלים בתוך handlers של requestAnimationFrame בכל פריים.

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

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

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

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

תיעוד ביצועים בכלי הפיתוח ל-Chrome

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

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

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

נמנעים ממיקרו-אופטימיזציה של JavaScript

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

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

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