מבוא
אחת מהתכונות החזקות שמאפיינות את JavaScript היא היכולת לפעול באופן אסינכרוני באמצעות פונקציות קריאה חוזרת. הקצאת פונקציות קריאה חוזרות אסינכרוניות מאפשרת לכתוב קוד מבוסס-אירועים, אבל היא גם הופכת את המעקב אחר באגים לחוויה מתסכלת, כי ה-JavaScript לא פועל באופן לינארי.
למרבה המזל, עכשיו אפשר לראות ב-Chrome DevTools את מקבץ הקריאות המלא של קריאות חזרה (callbacks) אסינכרוניות של JavaScript.
אחרי שתפעילו את התכונה 'מקבץ קריאות אסינכררוניות' בכלי הפיתוח, תוכלו להציג פירוט של מצב אפליקציית האינטרנט בנקודות זמן שונות. ניתוח מלא של נתיב הסטאק של חלק ממאזני האירועים, setInterval
, setTimeout
, XMLHttpRequest
, הבטחות (promises), requestAnimationFrame
, MutationObservers
ועוד.
כשבודקים את נתיב הסטאק, אפשר גם לנתח את הערך של כל משתנה בנקודה הספציפית הזו של ביצוע זמן הריצה. זה כמו מכונת זמן לביטויים שלכם בשעון!
נפעיל את התכונה הזו ונבחן כמה מהתרחישים האלה.
הפעלת ניפוי באגים אסינכרוני ב-Chrome
כדי לנסות את התכונה החדשה הזו, צריך להפעיל אותה ב-Chrome. עוברים לחלונית מקורות בכלי הפיתוח של Chrome Canary.
לצד החלונית Call Stack בצד שמאל, מופיעה תיבת סימון חדשה בשם 'Async'. מפעילים או משביתים את ניפוי הבאגים האסינכרוני באמצעות תיבת הסימון. (עם זאת, אחרי שמפעילים אותו, לא כדאי להשבית אותו לעולם).
תיעוד של אירועי טיימר עם עיכוב ותגובות XHR
סביר להניח שראית את ההודעה הזו בעבר ב-Gmail:
אם יש בעיה בשליחת הבקשה (אם יש בעיות בשרת או בעיות בחיבור לרשת בצד הלקוח), Gmail ינסה לשלוח שוב את ההודעה באופן אוטומטי אחרי זמן קצוב לתפוגה.
כדי להראות איך סטאקים של קריאות אסינכרניות יכולים לעזור לנו לנתח אירועי טיימר מושהים ותגובות XHR, יצרתי מחדש את התהליך הזה באמצעות דוגמה לדמיון של Gmail. הקוד המלא של JavaScript מופיע בקישור שלמעלה, אבל התהליך הוא:
אם תסתכלו רק בחלונית Call Stack בגרסאות קודמות של DevTools, נקודת העצירה ב-postOnFail()
תספק לכם מעט מידע על המקור שממנו postOnFail()
נקרא. אבל מה ההבדל כשמפעילים את סטאקים האסינכרוניים:
כשמפעילים את סטאקים של קריאות אסינכררוניות, אפשר לראות את כל סטאק הקריאות כדי לראות בקלות אם הבקשה הופעל מ-submitHandler()
(אחרי לחיצה על לחצן השליחה) או מ-retrySubmit()
(אחרי עיכוב של setTimeout()
):
מעקב אחר ביטויים באופן אסינכרוני
כשעוברים על סטאק הקריאות המלא, גם הביטויים שנצפו מתעדכנים כך שישקפו את המצב שבו הם היו באותו זמן.
הערכת קוד מתחומים קודמים
בנוסף למעקב אחרי ביטויים, אפשר לבצע פעולות בקוד מתחומים קודמים ישירות בחלונית מסוף JavaScript של DevTools.
נניח שאתם ד'ר הו ודרוש לכם קצת עזרה בהשוואת השעון שלפני שנכנסתם ל-Tardis ל'עכשיו'. במסוף DevTools אפשר להעריך, לאחסן ולבצע חישובים של ערכים ממספר נקודות ביצוע שונות בקלות.
שימוש בכלי הפיתוח כדי לבצע שינויים בביטויים חוסך זמן, כי לא צריך לחזור לקוד המקור, לבצע שינויים ולרענן את הדפדפן.
פתרון של הבטחות שרשורו
אם חשבתם שהתהליך הקודם של Gmail היה קשה לפענוח בלי הפעלת התכונה של סטאק הקריאות האסינכרוניות, תוכלו לדמיין כמה קשה יהיה לפתור תהליכים אסינכרונים מורכבים יותר, כמו הבטחות שרשומות בשרשור? נבחן שוב את הדוגמה האחרונה במדריך של Jake Archibald בנושא Promises ב-JavaScript.
הנה אנימציה קצרה של הליכה בסטאקים של הקריאות בדוגמה של Jake async-best-example.html.
קבלת תובנות לגבי אנימציות באתר
נמשיך להתעמק בארכיונים של HTML5Rocks. זוכרים את המאמר של פול לואיס בנושא אנימציות יעילות, מהירות וחזקות יותר באמצעות requestAnimationFrame?
פותחים את הדמו של requestAnimationFrame ומוסיפים נקודת עצירה בתחילת השיטה update() (בסביבות שורה 874) של post.html. בעזרת סטאקים של קריאות אסינכררוניות אנחנו מקבלים הרבה יותר תובנות לגבי requestAnimationFrame, כולל היכולת לחזור כל הדרך אל פונקציית ה-callback של אירוע הגלילה שהתחיל את התהליך.
מעקב אחר עדכוני DOM כשמשתמשים ב-MutationObserver
MutationObserver
מאפשרים לנו לזהות שינויים ב-DOM. בדוגמה הפשוטה הזו, כשלוחצים על הלחצן, צומת DOM חדש מצורף ל-<div class="rows"></div>
.
מוסיפים נקודת עצירה ב-nodeAdded()
(שורה 31) בקובץ demo.html. כשמפעילים את סטאקים של קריאות אסינכררוניות, אפשר עכשיו לעבור בסטאק הקריאות חזרה דרך addNode()
לאירוע הקליק הראשוני.
טיפים לניפוי באגים ב-JavaScript בסטאקים של קריאות אסינכרוניות
מתן שמות לפונקציות
אם אתם נוטים להקצות את כל הפונקציות החוזרות כפונקציות אנונימיות, מומלץ לתת להן שם כדי שיהיה קל יותר להציג את סטאק הקריאות.
לדוגמה, ניקח פונקציה אנונימית כזו:
window.addEventListener('load', function() {
// do something
});
נותנים לו שם כמו windowLoaded()
:
window.addEventListener('load', function <strong>windowLoaded</strong>(){
// do something
});
כשאירוע הטעינה יופעל, הוא יופיע ב-DevTools בתרשים סטאק עם שם הפונקציה במקום עם הכיתוב המסתורי (anonymous function). כך קל יותר לראות במבט מהיר מה קורה ב-stack trace.
המשך למידה
לסיכום, אלה כל פונקציות ה-callbacks האסינכרוניות שבהן סטאק הקריאות המלא יוצג בכלי הפיתוח:
- טיימרים: חוזרים למקום שבו
setTimeout()
אוsetInterval()
הופעלו. - בקשות XHR: חוזרים אחורה למקום שבו
xhr.send()
נקרא. - מסגרות אנימציה: חוזרים אחורה למקום שבו
requestAnimationFrame
נקרא. - Promises: אפשר לחזור אחורה למקום שבו התבצעה התאמת נתונים ל-Promise.
- Object.observe: חוזרים למקום שבו פונקציית ה-callback של הצופה אוחדה במקור.
- MutationObservers: חוזרים אחורה למקום שבו הופעל האירוע של Mutation Observer.
- window.postMessage(): ניתוח של קריאות להעברת הודעות בתוך תהליך.
- DataTransferItem.getAsString()
- FileSystem API
- IndexedDB
- WebSQL
- אירועי DOM שעומדים בדרישות דרך
addEventListener()
: עוברים חזרה למקום שבו האירוע הופעל. מסיבות שקשורות לביצועים, לא כל אירועי ה-DOM עומדים בדרישות לשימוש בתכונה 'מחסומי קריאות אסינכרוני'. דוגמאות לאירועים שזמינים כרגע: 'scroll', 'hashchange' ו-'selectionchange'. - אירועי מולטימדיה דרך
addEventListener()
: חוזרים למקום שבו האירוע הופעל. אירועי המולטימדיה הזמינים כוללים: אירועי אודיו ווידאו (למשל 'play', 'pause', 'ratechange'), אירועי WebRTC MediaStreamTrackList (למשל 'addtrack', 'removetrack') ואירועי MediaSource (למשל 'sourceopen').
היכולת לראות את מעקב הסטאק המלא של פונקציות ה-callbacks ב-JavaScript אמורה להרגיע אתכם. התכונה הזו ב-DevTools תעזור במיוחד כשמתרחשים כמה אירועים אסינכררוניים ביחס זה לזה, או אם חריגה שלא תפסתם נזרקת מתוך קריאה חוזרת אסינכררונית.
כדאי לנסות את התכונה ב-Chrome. אם יש לכם משוב על התכונה החדשה הזו, תוכלו לכתוב לנו בכלי למעקב אחר באגים של כלי הפיתוח ל-Chrome או בקבוצת כלי הפיתוח ל-Chrome.