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