บทนำ
ฟีเจอร์ที่มีประสิทธิภาพซึ่งทำให้ JavaScript โดดเด่นคือความสามารถในการทํางานแบบไม่สอดคล้องกันผ่านฟังก์ชัน Callback การกำหนดการเรียกกลับแบบแอซิงโครนัสช่วยให้คุณเขียนโค้ดที่ทำงานตามเหตุการณ์ได้ แต่ก็ทำให้การติดตามข้อบกพร่องเป็นเรื่องยากขึ้นด้วย เนื่องจาก JavaScript ไม่ได้ทำงานแบบเป็นเส้นตรง
แต่ตอนนี้คุณดูกองคําเรียกทั้งหมดของคอลแบ็ก JavaScript แบบไม่สอดคล้องกันได้ใน Chrome DevTools

เมื่อเปิดใช้ฟีเจอร์สแต็กการเรียกแบบแอซิงค์ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์แล้ว คุณจะเจาะลึกสถานะของเว็บแอป ณ เวลาต่างๆ ได้ แสดงสแต็กเทรซแบบเต็มสําหรับโปรแกรมรับฟังเหตุการณ์บางรายการ, setInterval
,setTimeout
, XMLHttpRequest
,
สัญญา requestAnimationFrame
, MutationObservers
และอื่นๆ
ขณะดูสแต็กเทรซ คุณสามารถวิเคราะห์ค่าของตัวแปร ณ จุดใดก็ได้ของรันไทม์ ฟีเจอร์นี้เปรียบเสมือนไทม์แมชชีนสำหรับการแสดงออกของใบหน้า
มาเปิดใช้ฟีเจอร์นี้และดูสถานการณ์จำลองบางส่วนกัน
เปิดใช้การแก้ไขข้อบกพร่องแบบไม่พร้อมกันใน Chrome
ลองใช้ฟีเจอร์ใหม่นี้โดยเปิดใช้ใน Chrome ไปที่แผงแหล่งที่มาของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome Canary
ถัดจากแผง Call Stack ทางด้านขวามือจะมีช่องทําเครื่องหมายใหม่สําหรับ "Async" สลับช่องทำเครื่องหมายเพื่อเปิดหรือปิดการแก้ไขข้อบกพร่องแบบแอซิงค์ (แต่เมื่อเปิดแล้ว คุณอาจไม่ต้องการปิดอีกเลย)

บันทึกเหตุการณ์ตัวจับเวลาแบบล่าช้าและการตอบกลับ XHR
คุณอาจเคยเห็นสิ่งนี้ใน Gmail มาก่อน

หากมีปัญหาในการส่งคำขอ (เซิร์ฟเวอร์มีปัญหาหรือมีปัญหาการเชื่อมต่อเครือข่ายในฝั่งไคลเอ็นต์) Gmail จะพยายามส่งข้อความอีกครั้งโดยอัตโนมัติหลังจากหมดเวลาสั้นๆ
หากต้องการดูว่าสแต็กการเรียกแบบแอซิงค์ช่วยเราวิเคราะห์เหตุการณ์ตัวจับเวลาแบบเลื่อนเวลาและคำตอบ XHR ได้อย่างไร เราจึงได้สร้างขั้นตอนดังกล่าวอีกครั้งโดยใช้ตัวอย่างจำลอง Gmail ดูโค้ด JavaScript ฉบับเต็มได้ในลิงก์ด้านบน แต่ขั้นตอนมีดังนี้

เมื่อดูที่แผงสแต็กการเรียกใช้ใน DevTools เวอร์ชันเก่าๆ เพียงอย่างเดียว จุดหยุดพักภายใน postOnFail()
จะให้ข้อมูลเพียงเล็กน้อยเกี่ยวกับตำแหน่งที่มีการเรียกใช้ postOnFail()
แต่ให้ดูความแตกต่างเมื่อเปิดใช้กองแบบไม่พร้อมกัน

คุณจะเห็นว่า postOnFail()
เริ่มต้นจาก AJAX Callback แต่ไม่มีข้อมูลเพิ่มเติม

คุณจะเห็นว่า XHR เริ่มต้นจาก submitHandler()
ดีมาก
เมื่อเปิดสแต็กการเรียกแบบแอซิงค์ คุณจะดูสแต็กการเรียกทั้งหมดเพื่อดูว่าคําขอเริ่มต้นจาก submitHandler()
(ซึ่งเกิดขึ้นหลังจากคลิกปุ่ม "ส่ง") หรือจาก retrySubmit()
(ซึ่งเกิดขึ้นหลังจากการรอ setTimeout()
วินาที) ได้โดยง่าย


ดูนิพจน์การดูแบบอะซิงโครนัส
เมื่อคุณเดินผ่านกองซ้อนการเรียกทั้งหมด นิพจน์ที่ดูอยู่จะอัปเดตเพื่อแสดงสถานะ ณ ขณะนั้นด้วย

ประเมินโค้ดจากขอบเขตที่ผ่านมา
นอกจากการดูนิพจน์แล้ว คุณยังโต้ตอบกับโค้ดจากขอบเขตก่อนหน้าได้ในแผงคอนโซล JavaScript ของเครื่องมือสำหรับนักพัฒนาเว็บ
ลองจินตนาการว่าคุณเป็น Dr. Who และต้องการความช่วยเหลือเล็กน้อยในการเปรียบเทียบนาฬิกาจากก่อนขึ้น Tardis กับ "ตอนนี้" จากคอนโซล DevTools คุณสามารถประเมิน จัดเก็บ และทำการคำนวณค่าจากจุดดำเนินการต่างๆ ได้อย่างง่ายดาย

การอยู่ในเครื่องมือสำหรับนักพัฒนาเว็บเพื่อจัดการนิพจน์จะช่วยประหยัดเวลาในการต้องกลับไปที่ซอร์สโค้ด แก้ไข และรีเฟรชเบราว์เซอร์
แก้ปัญหาการแก้ไขสัญญาแบบเชน
หากคุณคิดว่าการแยกแยะขั้นตอนจำลองของ Gmail ก่อนหน้านี้นั้นยากอยู่แล้ว หากไม่ได้เปิดใช้ฟีเจอร์สแต็กการเรียกแบบแอซิงโครนัส คุณลองจินตนาการดูว่าขั้นตอนที่ซับซ้อนมากขึ้นแบบแอซิงโครนัส เช่น พรอมต์แบบเชน จะยากขนาดไหน มาดูตัวอย่างสุดท้ายของบทแนะนำเกี่ยวกับสัญญา JavaScript ของ Jake Archibald กัน
ต่อไปนี้คือภาพเคลื่อนไหวสั้นๆ ของการเรียกใช้สแต็กการเรียกในตัวอย่าง async-best-example.html ของ Jake

สังเกตว่าแผงกองซ้อนการเรียกมีข้อมูลน้อยมากเมื่อพยายามแก้ไขข้อบกพร่องของ Promise

ว้าว คำสัญญาดังกล่าว การติดต่อกลับจำนวนมาก
รับข้อมูลเชิงลึกเกี่ยวกับภาพเคลื่อนไหวบนเว็บ
มาดูรายละเอียดเพิ่มเติมจากที่เก็บ HTML5Rocks จำบทความของ Paul Lewis เรื่องภาพเคลื่อนไหวที่เบาลง มีประสิทธิภาพมากขึ้น และเร็วขึ้นด้วย requestAnimationFrame ได้ไหม
เปิดการสาธิต requestAnimationFrame และเพิ่มจุดหยุดพักที่จุดเริ่มต้นของเมธอด update() (ประมาณบรรทัด 874) ของ post.html สแต็กการเรียกแบบแอซิงค์ช่วยให้เราได้รับข้อมูลเชิงลึกเพิ่มเติมเกี่ยวกับ requestAnimationFrame รวมถึงสามารถย้อนกลับไปยังการเรียกกลับเหตุการณ์การเลื่อนที่เริ่มต้น


ติดตามการอัปเดต 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 พร้อมชื่อฟังก์ชันแทน "(ฟังก์ชันที่ไม่ระบุชื่อ)" ที่เป็นรหัส ซึ่งจะช่วยให้คุณเห็นสิ่งที่เกิดขึ้นในสแต็กเทรซได้อย่างรวดเร็ว


สำรวจเพิ่มเติม
โดยสรุปแล้ว รายการต่อไปนี้คือคอลแบ็กแบบแอซิงโครนัสทั้งหมดที่เครื่องมือสำหรับนักพัฒนาซอฟต์แวร์จะแสดงสแต็กการเรียกทั้งหมด
- ตัวจับเวลา:
เดินกลับไปที่จุดเริ่มต้น
setTimeout()
หรือsetInterval()
- XHR:
กลับไปที่ตำแหน่งที่เรียก
xhr.send()
- เฟรมภาพเคลื่อนไหว:
เดินกลับไปที่เรียก
requestAnimationFrame
- Promises: กลับไปที่ Promise ที่ได้รับการแก้ไขแล้ว
- Object.observe: กลับไปที่ตำแหน่งที่ผูกการเรียกกลับของ Observer ไว้ตั้งแต่แรก
- MutationObservers: กลับไปที่จุดที่เหตุการณ์ MutationObserver เริ่มทํางาน
- window.postMessage(): เรียกใช้การเรียกใช้การรับส่งข้อความภายในกระบวนการ
- DataTransferItem.getAsString()
- FileSystem API
- IndexedDB
- WebSQL
- เหตุการณ์ DOM ที่มีสิทธิ์ผ่าน
addEventListener()
: กลับไปที่จุดที่เรียกเหตุการณ์ให้แสดง กิจกรรม DOM บางรายการไม่มีสิทธิ์ใช้ฟีเจอร์สแต็กการเรียกแบบแอซิงค์เนื่องจากเหตุผลด้านประสิทธิภาพ ตัวอย่างเหตุการณ์ที่ใช้ได้ในปัจจุบัน ได้แก่ "scroll", "hashchange" และ "selectionchange" - เหตุการณ์มัลติมีเดียผ่าน
addEventListener()
: ย้อนกลับไปยังจุดที่เหตุการณ์เริ่มทํางาน เหตุการณ์มัลติมีเดียที่ใช้ได้มีดังนี้ เหตุการณ์เสียงและวิดีโอ (เช่น "play", "pause", "ratechange"), เหตุการณ์ MediaStreamTrackList ของ WebRTC (เช่น "addtrack", "removetrack") และเหตุการณ์ MediaSource (เช่น "sourceopen")
การดูสแต็กเทรซแบบเต็มของคอลแบ็ก JavaScript จะช่วยคุณแก้ปัญหาได้ ฟีเจอร์นี้ในเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์จะมีประโยชน์อย่างยิ่งเมื่อเกิดเหตุการณ์แบบแอสซิงค์หลายรายการซึ่งสัมพันธ์กัน หรือหากมีการยกเว้นที่ตรวจไม่พบจากภายในการเรียกกลับแบบแอสซิงค์
ลองใช้ใน Chrome หากมีความคิดเห็นเกี่ยวกับฟีเจอร์ใหม่นี้ โปรดส่งอีเมลถึงเราในเครื่องมือติดตามข้อบกพร่องของเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome หรือในกลุ่มเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome