ממשק API לתזמון משתמש

הסבר על אפליקציית האינטרנט

Alex Danilo

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

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

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

זמן ברזולוציה גבוהה ו-now()

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

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

var myTime = window.performance.now();

קיים ממשק נוסף בשם PerformanceTiming (תזמונים) שמספק מספר פעמים שונות הקשורות לאופן הטעינה של אפליקציית האינטרנט. השיטה now() מחזירה את הזמן שחלף מהמועד שבו התרחש הזמן navigationStart ב-PerformanceTiming.

סוג DOMHighResTimeStamp

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

ממשק תזמון המשתמש

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

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

שימוש ב-mark()

השיטה mark() היא הכלי הראשי בערכת הכלים לניתוח לוחות זמנים. מה ש-mark() עושה זה לשמור עבורנו חותמת זמן. מאוד שימושי בmark() הוא שאפשר לתת שם לחותמת הזמן, וה-API יזכור את השם ואת חותמת הזמן כיחידה אחת.

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

המפרט כולל כמה הצעות לשמות לסימנים שעשויים להיות מעניינים, כאלה מובנים מאליהם, כמו mark_fully_loaded,mark_fully_visible, mark_above_the_fold וכו'.

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

window.performance.mark('mark_fully_loaded');

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

חישוב המדידות באמצעות measure()

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

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

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

window.performance.measure('measure_load_from_dom', 'domComplete', 'mark_fully_loaded');

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

מחיקת הסימנים עם clearMarks()

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

אפשר להסיר בקלות סימנים שהוגדרו על ידי התקשרות למספר clearMarks().

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

window.performance.clearMarks();

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

window.peformance.clearMarks('mark_fully_loaded');

מסיר את הסימן שהגדרנו בדוגמה הראשונה ומשאיר את כל הסימנים האחרים שהגדרנו ללא שינוי.

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

window.performance.clearMeasures('measure_load_from_dom');

תסיר את המדד שביצענו בדוגמה שלמעלה (measure()). אם רוצים להסיר את כל המדדים, הפונקציה פועלת בדיוק כמו הפונקציה clearMarks() - פשוט קוראים לפונקציה clearMeasures() ללא ארגומנטים.

הוצאת נתוני התזמון

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

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

הקוד הבא:

var items = window.performance.getEntriesByType('mark');

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

var items = window.performance.getEntriesByType('measure');

מחזיר לנו רשימה של כל הפעולות שביצענו.

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

var items = window.performance.getEntriesByName('mark_fully_loaded');

תחזיר לנו רשימה שיש בה פריט אחד שמכיל את חותמת הזמן 'mark_full_loaded' במאפיין startTime.

תזמון בקשת XHR (דוגמה)

עכשיו, כשיש לנו תמונה ברורה של ה-User Timing API, נוכל להשתמש בו כדי לנתח את משך הזמן שנדרש ל-XMLHttpRequests באפליקציית האינטרנט שלנו.

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

בדרך כלל ה-XMLHttpRequest שלנו ייראה כך:

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  do_something(e.responseText);
}
myReq.send();

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

var reqCnt = 0;

var myReq = new XMLHttpRequest();
myReq.open('GET', url, true);
myReq.onload = function(e) {
  window.performance.mark('mark_end_xhr');
  reqCnt++;
  window.performance.measure('measure_xhr_' + reqCnt, 'mark_start_xhr', 'mark_end_xhr');
  do_something(e.responseText);
}
window.performance.mark('mark_start_xhr');
myReq.send();

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

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

var items = window.performance.getEntriesByType('measure');
for (var i = 0; i < items.length; ++i) {
  var req = items[i];
  console.log('XHR ' + req.name + ' took ' + req.duration + 'ms');
}

סיכום

User Timing API נותן לך הרבה כלים נהדרים ליישום בכל היבט של אפליקציית האינטרנט שלך. ניתן לצמצם את הנקודות החמות באפליקציה בקלות על ידי פיזור קריאות ל-API על פני אפליקציית האינטרנט ולאחר עיבוד נתוני התזמון שנוצרו כדי ליצור תמונה ברורה של המקום שבו הזמן מנוצל. אבל מה קורה אם הדפדפן שלכם לא תומך ב-API הזה? אין בעיה, אפשר למצוא כאן polyfill מצוין שמדמה את ה-API בצורה טובה ופועל יפה גם עם webpagetest.org. אנחנו מזמינים אותך להצטרף כבר עכשיו. אפשר לנסות את User Timing API באפליקציות שלך עכשיו. נסביר לך איך להאיץ אותן והמשתמשים יודה לך על כך ששיפרת את החוויה שלהם.