เทคนิคการดีบักที่ใช้ในเบราว์เซอร์
(alan.norbauer.com)- หากคุณใช้งานเครื่องมือสำหรับนักพัฒนาในเบราว์เซอร์ได้ในระดับกลางขึ้นไป คุณสามารถขยาย conditional breakpoint ให้เป็นมากกว่าเงื่อนไขหยุดธรรมดา และใช้เป็นเครื่องมือสำหรับบันทึกล็อก ติดตามสถานะ เปลี่ยนสถานะ และวัดเวลาได้
- ถ้านำ Console API อย่าง
console.log,console.count,console.trace,console.timeไปใส่ไว้ใน breakpoint หรือ Watch Pane ก็จะสามารถบันทึก flow การทำงานและสถานะได้โดยไม่ต้องหยุดการทำงาน - เมื่อผสานจำนวนอาร์กิวเมนต์ของฟังก์ชัน เวลา ค่า CSS ที่คำนวณแล้ว จำนวนครั้งที่รัน การสุ่มตัวอย่าง และ global boolean เข้าด้วยกัน ก็จะควบคุม จังหวะที่หยุด ได้ละเอียดขึ้นมาก
monitor,debug,copy,$0,getEventListeners,monitorEventsของ Chrome ช่วยให้จัดการการเรียกใช้ฟังก์ชัน, DOM, อีเวนต์ และงานเกี่ยวกับคลิปบอร์ดได้อย่างรวดเร็วจากคอนโซล- บนหน้าจอที่ DOM เปลี่ยนตลอดจาก JS หรืออีเวนต์ของผู้ใช้ การหยุด JS ชั่วคราว,
setTimeout(debugger), DOM snapshot และการเฝ้าดู focus มีประโยชน์มากเป็นพิเศษกับ การดีบัก HTML/CSS
ขยาย conditional breakpoint ให้เป็นเครื่องมือดีบัก
-
ใน conditional breakpoint ใส่ได้ไม่ใช่แค่เงื่อนไขจริง/เท็จ แต่ยังใส่ JavaScript expression ที่มี side effect ได้ด้วย
-
ถ้าใช้ให้เป็น คุณสามารถเปลี่ยน breakpoint ปกติให้กลายเป็นเครื่องมือสำหรับบันทึกล็อก ติดตาม เปลี่ยนสถานะ และวัดเวลาได้
-
Logpoint และ tracepoint
- ถ้าเรียก
console.logใน conditional breakpoint มันจะทำงานเหมือน logpoint ที่พิมพ์ค่าออกคอนโซลโดยไม่หยุดการทำงาน - ถ้าใช้
console.countก็จะนับได้ด้วยว่าบรรทัดนั้นถูกรันไปกี่ครั้ง - ณ อัปเดตเดือนพฤษภาคม 2020 เบราว์เซอร์หลักรองรับ logpoint/tracepoint โดยตรงแล้ว
- ถ้าเรียก
-
ใช้ Console API ใน Watch Pane
- ใน Watch Pane ก็ใส่ expression อย่าง
console.logได้เช่นกัน - ทุกครั้งที่แอปพลิเคชันหยุดอยู่ที่ debugger คุณสามารถใช้
console.table(localStorage)เพื่อเก็บ snapshot ของ localStorage ได้ - ถ้าใช้ DOM change breakpoint ร่วมกับ Watch expression ก็สามารถเก็บ snapshot หลังจาก DOM subtree เปลี่ยนไว้ในอาร์เรย์ได้
(window.doms = window.doms || []).push(document.documentElement.outerHTML)- DOM change breakpoint ไม่สามารถตั้งให้ไม่หยุดการทำงานได้
- ใน Watch Pane ก็ใส่ expression อย่าง
-
ติดตาม call stack
- ถ้ามีฟังก์ชันสำหรับแสดง loading spinner กับซ่อน spinner และคุณกำลังหาอาการที่มีแต่การเรียกแสดงค้างอยู่ คุณสามารถใส่
console.traceลงใน conditional breakpoint ได้ - จาก stack trace ล่าสุดของฟังก์ชันแสดง คุณสามารถคลิก caller เพื่อย้ายไปยังตำแหน่งที่เรียกใช้นั้นได้
- ถ้ามีฟังก์ชันสำหรับแสดง loading spinner กับซ่อน spinner และคุณกำลังหาอาการที่มีแต่การเรียกแสดงค้างอยู่ คุณสามารถใส่
-
เปลี่ยนพฤติกรรมโปรแกรมระหว่างรัน
- ถ้าเขียนทับอาร์กิวเมนต์ของฟังก์ชันใน expression ของ conditional breakpoint ก็สามารถเปลี่ยน พฤติกรรมของโปรแกรม แบบสด ๆ ในเบราว์เซอร์ได้
- เช่น คุณสามารถเปลี่ยนค่า
idของฟังก์ชันgetPersonได้ - expression อย่าง
id=1จะประเมินค่าเป็นจริงและทำให้ debugger หยุด ดังนั้นถ้าไม่อยากให้หยุด ให้ต่อท้ายด้วย, false
-
วัดประสิทธิภาพแบบรวดเร็ว
- เนื่องจากเวลาในการประเมิน conditional breakpoint จะปนอยู่ด้วย จึงไม่เหมาะกับการทำ performance profiling แบบละเอียด
- แต่ถ้าต้องการวัดแบบเร็ว ๆ ก็สามารถใส่
console.time('label')ที่เงื่อนไขจุดเริ่มต้น และconsole.timeEnd('label')ที่เงื่อนไขจุดสิ้นสุด เพื่อบันทึกเวลาในการทำงานลงคอนโซลได้
ทำเงื่อนไขการหยุดให้ละเอียดขึ้น
-
ใช้จำนวนอาร์กิวเมนต์ของฟังก์ชัน
- ถ้าต้องการหยุดเฉพาะตอนที่ฟังก์ชันปัจจุบันถูกเรียกด้วย 3 อาร์กิวเมนต์ ให้ใช้เงื่อนไขนี้
arguments.callee.length === 3- มีประโยชน์กับ overloaded function ที่มี optional argument
- ถ้าต้องการหยุดเฉพาะเมื่อจำนวนอาร์กิวเมนต์ที่ประกาศไว้กับจำนวนที่ส่งเข้ามาจริงไม่เท่ากัน ให้ใช้เงื่อนไขนี้
(arguments.callee.length) != arguments.length- ช่วยหา bug ที่ตำแหน่งเรียกใช้ฟังก์ชันได้
-
เงื่อนไขตามเวลา
- ถ้าไม่ต้องการให้หยุดก่อนผ่านไป 5 วินาทีหลังโหลดหน้า ให้ใช้เงื่อนไขนี้
performance.now() > 5000- เหมาะเมื่อคุณสนใจ breakpoint เฉพาะหลังจากการโหลดหน้าเริ่มต้นเสร็จแล้ว
- ถ้าต้องการให้ไม่หยุดในช่วง 5 วินาทีแรกหลังตั้ง breakpoint แต่หลังจากนั้นค่อยหยุด ให้เก็บเวลาอ้างอิงไว้ในตัวแปร global
window.baseline = window.baseline || Date.now(), (Date.now() - window.baseline) > 5000- คุณสามารถรีสตาร์ตตัวนับได้จากคอนโซลด้วย
window.baseline = Date.now()
-
เงื่อนไขตามสถานะ CSS
- สามารถใช้ค่า CSS ที่คำนวณแล้วเป็นเงื่อนไขในการหยุดได้
- เช่น ถ้าต้องการหยุดเฉพาะตอนที่สีพื้นหลังของ
document.bodyเป็นสีแดง ให้ใช้เงื่อนไขนี้
window.getComputedStyle(document.body).backgroundColor === "rgb(255,0,0)" -
จำนวนครั้งที่รันและการสุ่มตัวอย่าง
- สามารถเพิ่มตัวนับทุกครั้งที่บรรทัดนั้นถูกรัน เพื่อให้ หยุดแค่ทุก ๆ 2 ครั้ง ได้
window.counter = (window.counter || 0) + 1, window.counter % 2 === 0- ถ้าต้องการสุ่มหยุดเพียง 1 ใน 10 ครั้ง ให้ใช้เงื่อนไขนี้
Math.random() < 0.1 -
ไม่หยุดเด็ดขาดในบางตำแหน่ง
- ใน Chrome ถ้าคลิกขวาที่ gutter แล้วเลือก “Never Pause Here” จะมีการสร้าง conditional breakpoint ที่เป็น
falseเสมอ ทำให้ไม่หยุดที่บรรทัดนั้น - ใช้ได้ตอนต้องการตัดบางบรรทัดออกจาก XHR breakpoint หรือเพิกเฉย exception บางรายการ
- ใน Chrome ถ้าคลิกขวาที่ gutter แล้วเลือก “Never Pause Here” จะมีการสร้าง conditional breakpoint ที่เป็น
-
กำหนด instance ID อัตโนมัติ
- คุณสามารถใส่ conditional breakpoint ใน constructor ของคลาสเพื่อเก็บแต่ละ instance ลงในอาร์เรย์ได้
(window.instances = window.instances || []).push(this)- ID เฉพาะของ instance หนึ่ง ๆ สามารถดูได้จาก index ในอาร์เรย์
window.instances.indexOf(instance) -
สวิตช์เปิดปิด breakpoint แบบ global
- คุณสามารถควบคุม conditional breakpoint หนึ่งจุดหรือหลายจุดด้วย global boolean ได้
- จะเปลี่ยนค่าจากคอนโซลโดยตรง เปลี่ยนจาก breakpoint อื่น หรือเปลี่ยนด้วย timer ก็ได้
window.enableBreakpoints = true setTimeout(() => (window.enableBreakpoints = true), 5000)
ติดตามการเรียกใช้ฟังก์ชันและคลาส
-
เฝ้าดูการเรียกใช้ method ของคลาส
- ถ้าใช้เมธอดบรรทัดคำสั่ง
monitorของ Chrome ก็จะติดตามการเรียกใช้ method ของคลาสได้ง่าย - ถ้าต้องการดูการเรียก method ของทุก instance ของคลาส
Dogก็สามารถใช้monitorกับทุกพร็อพเพอร์ตีของ prototype ได้
var p = Dog.prototype; Object.getOwnPropertyNames(p).forEach((k) => monitor(p[k]));- ในคอนโซลจะพิมพ์ข้อมูลการเรียกออกมา เช่น
function bark called with arguments: 2 - ถ้าไม่อยากแค่บันทึกล็อก แต่อยากให้หยุดตอนถูกเรียกด้วย ก็ใช้
debugแทนmonitorได้
- ถ้าใช้เมธอดบรรทัดคำสั่ง
-
ติดตามคลาสจาก instance เฉพาะตัว
- ถ้าไม่รู้ชื่อคลาสแต่มี instance อยู่ ก็สามารถเฝ้าดูได้แบบเดียวกันผ่าน prototype ของ constructor
var p = instance.constructor.prototype; Object.getOwnPropertyNames(p).forEach((k) => monitor(p[k]));- มีประโยชน์เมื่ออยากสร้างฟังก์ชันที่ทำงานกับ instance ใดก็ได้โดยไม่ยึดกับคลาสเฉพาะ
-
ดีบักจากคอนโซลก่อนเรียกใช้ฟังก์ชัน
- ก่อนจะเรียกฟังก์ชันที่ต้องการดีบักจากคอนโซล ให้รัน
debuggerก่อน แล้ว Step into ไปกับการเรียกฟังก์ชันถัดไป เพื่อเข้าไปใน implementation ของฟังก์ชันได้
debugger; fn(1);- มีประโยชน์เมื่อขี้เกียจไล่หาตำแหน่งที่ประกาศฟังก์ชัน หรือเมื่อ
fnถูก bind แบบไดนามิกจนไม่รู้ตำแหน่งในซอร์ส - ใน Chrome คุณยังเรียก
debug(fn)เพื่อให้หยุดในฟังก์ชันทุกครั้งที่fnถูกเรียกได้ด้วย
- ก่อนจะเรียกฟังก์ชันที่ต้องการดีบักจากคอนโซล ให้รัน
ดีบักการเปลี่ยน URL และการอ่านพร็อพเพอร์ตี
-
หยุดก่อน SPA routing
- ถ้าต้องการหยุดก่อนที่ single-page application จะเปลี่ยน URL ให้ผูกฟังก์ชันที่มี
debuggerเข้ากับhistory.pushState,history.replaceState,window.onhashchange,window.onpopstate
const dbg = () => { debugger; }; history.pushState = dbg; history.replaceState = dbg; window.onhashchange = dbg; window.onpopstate = dbg;- เวอร์ชันของ
dbgนี้ยังไม่ได้รวม implementation ที่หยุดโดยไม่ทำให้ navigation พัง - ในกรณีที่เรียก
window.location.replaceหรือwindow.location.assignโดยตรง หน้าจะ unload ทันทีหลังการ assign จึงจัดการด้วยวิธีนี้ไม่ได้ - ใน Chrome สามารถใช้
debugกับเมธอดที่เกี่ยวข้องเพื่อดู source ของ redirect และสถานะในจังหวะนั้นได้
debug(window.location.replace); debug(window.location.assign); - ถ้าต้องการหยุดก่อนที่ single-page application จะเปลี่ยน URL ให้ผูกฟังก์ชันที่มี
-
หาให้เจอว่ามีการอ่านพร็อพเพอร์ตีตรงไหน
- ถ้าต้องการรู้จังหวะที่มีการอ่าน property ใด property หนึ่งของออบเจ็กต์ สามารถใส่
debuggerไว้ใน getter ได้
{ get configOption() { debugger; return true; } }- มีประโยชน์เมื่อต้องการดูว่าโค้ดใดใช้ option การตั้งค่านั้นอย่างไร
- จะปรับจากซอร์สต้นฉบับโดยตรง หรือใช้ conditional breakpoint เพื่อทำแบบเดียวกันก็ได้
- ถ้าต้องการรู้จังหวะที่มีการอ่าน property ใด property หนึ่งของออบเจ็กต์ สามารถใส่
คัดลอกข้อมูลจากคอนโซล
- ถ้าใช้ Console API
copy()คุณจะคัดลอกข้อมูลจากเบราว์เซอร์ไปยัง คลิปบอร์ด ได้โดยไม่โดนตัดสตริง - ใช้ได้กับการคัดลอก DOM snapshot ปัจจุบัน, metadata ของ resource อย่างรูปภาพ, JSON blob ขนาดใหญ่, และ dump ของ localStorage
copy(document.documentElement.outerHTML)
copy(performance.getEntriesByType("resource"))
copy(JSON.parse(blob))
copy(localStorage)
การดีบัก HTML/CSS
-
ตรวจ DOM ขณะ JS หยุดอยู่
- ใน DOM inspector ของ Chrome/Windows ถ้ากด
ctrl+\ก็จะหยุดการทำงานของ JS ได้ทุกเมื่อ - แม้ในสถานการณ์ที่ JS เปลี่ยน DOM หรืออีเวนต์อย่าง mouseover เปลี่ยน DOM ก็ยังตรวจดู DOM snapshot ปัจจุบัน ได้อย่างเสถียร
- ใน DOM inspector ของ Chrome/Windows ถ้ากด
-
ตรวจองค์ประกอบที่หายไป
- องค์ประกอบ DOM แบบมีเงื่อนไขที่หายไปเมื่อขยับเมาส์ สามารถตรวจได้โดยตั้ง timer 5 วินาทีในคอนโซลให้รัน debugger
setTimeout(function() { debugger; }, 5000);- เมื่อเปิด UI ทิ้งไว้ 5 วินาทีแล้ว JS หยุดทำงาน องค์ประกอบจะไม่หายไป จึงย้ายไปที่เครื่องมือสำหรับนักพัฒนาเพื่อตรวจได้
- ระหว่างที่ JS หยุดอยู่ คุณสามารถตรวจ element, แก้ CSS และสั่งคำสั่ง JS จากคอนโซลได้
- มีประสิทธิภาพมากเมื่อจะตรวจ DOM ที่ขึ้นกับตำแหน่งเคอร์เซอร์หรือ focus
-
บันทึก DOM snapshot
- ถ้าต้องการคัดลอก DOM ปัจจุบัน ให้ใช้คำสั่งนี้
copy(document.documentElement.outerHTML);- ถ้าต้องการเก็บสตริง DOM ลงอาร์เรย์ทุก 1 วินาที ก็ใช้
setIntervalแบบนี้
doms = []; setInterval(() => { const domStr = document.documentElement.outerHTML; doms.push(domStr); }, 1000);- หรือจะไม่เก็บลงอาร์เรย์ แต่พิมพ์ออกคอนโซลเรื่อย ๆ ก็ได้
-
เฝ้าดู element ที่ได้รับ focus
- สามารถเทียบ
document.activeElementเป็นช่วง ๆ แล้วพิมพ์การเปลี่ยน focus ออกคอนโซลได้
(function () { let last = document.activeElement; setInterval(() => { if (document.activeElement !== last) { last = document.activeElement; console.log("Focus changed to: ", last); } }, 100); })(); - สามารถเทียบ
-
หา element ที่เป็นตัวหนา
- สามารถหา element ที่
fontWeightที่คำนวณแล้วเป็น"bold"หรือ"700"ได้จากทุก element
const isBold = (e) => { let w = window.getComputedStyle(e).fontWeight; return w === "bold" || w === "700"; }; Array.from(document.querySelectorAll("*")).filter(isBold);- ถ้าต้องการค้นหาเฉพาะในลูกหลานของ element ที่เลือกอยู่ใน inspector ตอนนี้ ก็ใช้
$0เป็นจุดอ้างอิงได้
Array.from($0.querySelectorAll("*")).filter(isBold); - สามารถหา element ที่
-
จัดการ element ที่เลือกอยู่และอีเวนต์
$0ในคอนโซลคือการอ้างอิงอัตโนมัติไปยัง element ที่เลือกอยู่ใน Element Inspector- ใน Chrome และ Edge สามารถเข้าถึง element ที่เคยตรวจไว้ก่อนหน้านั้นได้ผ่าน
$1,$2เป็นต้น - ใน Chrome สามารถดู event listener ของ element ที่เลือกอยู่ตอนนี้ได้
getEventListeners($0)- ถ้าต้องการดีบักทุกอีเวนต์ของ element ที่เลือกอยู่ ให้ใช้
monitorEvents($0) - ถ้าต้องการดูเฉพาะบางกลุ่มอีเวนต์ ก็ส่งอาร์เรย์เข้าไปได้
monitorEvents($0, ["control", "key"])
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ตลอดหลายทศวรรษที่ผ่านมา เครื่องมือดีบัก ที่ฝังมาในเบราว์เซอร์พัฒนาไปมากจริง ๆ
ในฐานะคนที่ใช้ JS มานาน รู้สึกขอบคุณอย่างมากต่อคนที่ทำให้การดีบักโค้ดในเบราว์เซอร์เป็นเรื่องที่เข้าใจง่ายได้ขนาดนี้
พอไปทำงานฝั่งแบ็กเอนด์หรือสายพัฒนาอื่น ๆ ก็จะคิดถึงระบบนิเวศของเครื่องมือดีบักที่เบราว์เซอร์สมัยใหม่ให้มานี้
ฉันดีบัก Python, Java, C++ มาเยอะหลายปี แต่ไม่เคยรู้สึกว่าเครื่องมือมันขาดอะไร
แน่นอนว่าเคยเห็นคนจำนวนมากที่ไม่รู้ว่ามีตัวเลือกอะไรให้ใช้ในสายนี้บ้าง
เจอแบบนั้นฉันยอมเลือกคอนโซลดีกว่า
setTimeout(function() { debugger; }, 5000);นี่ฉลาดมากสุดท้ายแล้ววิธีเดียวที่จะชนะสแตกเต่าเรียกซ้อนแบบรีเคอร์ซีฟที่ Chrome debugger ใช้ดีบักตัวเองได้ ก็คือ คำสั่ง
debuggerเท่านั้นsam.pl ของ Myspace Sammy worm อันลือลั่นก็ใช้กับดักดีบักเพื่อกันไม่ให้ผู้เยี่ยมชมไปขุดหน้าโฮมเพจ HTML ที่ถูกทำให้อ่านยาก
มันจะวนลูปหลักแล้วแทรกคำสั่ง
debugger;ที่น่ารำคาญไว้ทั่ว ๆ ไป พร้อมรันที่ช่วง 30FPS / 32ms เพื่อทำให้ DevTools ใช้งานไม่ได้เพราะไม่มีทาง “เพิกเฉย” ต่อคำสั่ง
debuggerได้cmd-\ได้หน้าจะหยุดที่บรรทัด JS ที่กำลังรันอยู่ แล้วคุณก็ตรวจสอบ element ที่มีปัญหาได้ตามปกติ
debuggerกรณีใช้งานคำสั่ง
debuggerแบบปกติที่ถูกต้องส่วนใหญ่ ถ้าคุณกำลังทำงานกับโค้ดของตัวเองอยู่ ก็แทนด้วย breakpoint ธรรมดาได้สังเกตว่าขาด
queryObjectsไปมันเป็น API ที่ค่อนข้างบ้าดี ซึ่งจะคืนรายการออบเจ็กต์ทั้งหมดที่สร้างจาก constructor ที่กำหนด
ตัวอย่างเช่น
queryObjects(Function)จะดึงรายการฟังก์ชันทั้งหมดใน heap ออกมาได้มันคืนค่าได้แม้กระทั่งฟังก์ชัน “private” ที่อยู่ในบางโมดูล
มันเป็นฟีเจอร์ที่บ้ามากจริง ๆ และน่าจะเป็น Chromium เท่านั้น
ฉันใช้งาน watch variable ไม่เคยได้เรื่องเลย
กฎเรื่องสโคปและการอัปเดต มันคลุมเครือเกินไป จนเหมือนว่าดูได้แค่ตัวแปร global แต่ถึงอย่างนั้นก็ยังไม่ทำงานตามที่คาด เลยลงเอยด้วยการถม log ค่าเต็มไปหมดเวลาทดสอบ
ฉันคิดมาหลายปีแล้วว่าควรมี UI สไตล์ Data.gui [1] ในคอนโซล เพื่อให้ดูและทดสอบค่าตัวแปรกับค่าคอนฟิกได้
ดูการทำงานจริงได้ใน CodePen [2] นี้
ในทางทฤษฎีเบราว์เซอร์มีฟีเจอร์ดีบักที่ยอดเยี่ยมเยอะมาก แต่ในทางปฏิบัติมันดูไม่ค่อยทำงานได้เสถียร
แม้แต่ breakpoint ก็ยังทำให้ทำงานได้เสถียรทั้งหมดไม่ได้
ตอนโค้ดไม่ถูก bundle ก็โอเค แต่พอ bundle เมื่อไร ต่อให้ยังไม่ minify ก็ดูเหมือนว่าฟีเจอร์ดีบักหลายอย่างจะพัง
ฉันไม่ใช่วิศวกรฟรอนต์เอนด์ เลยอาจกำลังทำอะไรผิดอยู่ก็ได้
มันน่าจะเป็นสาเหตุของความหงุดหงิดนี้ และฉันก็ยังไม่เข้าใจว่าทำไมประสบการณ์ดีบักแบบเปิดใช้งานมันอยู่ถึงแย่ขนาดนี้ แต่กลับถูกเปิดเป็นค่าเริ่มต้น
น่าจะดีถ้ามีวิธีเข้าถึง ตัวแปรภายในของ IIFE โดยไม่ต้องหยุดการทำงานของโค้ดในสโคป IIFE
มีวิธีโน้มน้าวดีบักเกอร์ให้ทำแบบนั้นได้ไหม?
https://en.m.wikipedia.org/wiki/Immediately_invoked_function...
แต่ถ้าอยู่นอก IIFE โดยสมบูรณ์ก็คงทำไม่ได้
ตัวแปรที่กำลังหาอาจไม่มีอยู่ในหน่วยความจำทั้งก่อนหรือหลังการทำงาน
JavaScript ไม่มีตัวแปรแบบสแตติกเหมือนภาษาอื่น ดังนั้นทุกครั้งที่ IIFE ถูกเรียก ตัวแปรภายในก็จะถูกทิ้งไป
JavaScript มีโมเดลแบบเธรดเดี่ยวที่ค่อนข้างเข้มแข็ง เว้นแต่จะใช้สิ่งอย่าง web worker ดังนั้นถ้าไม่ได้พยายามสร้าง race condition ด้วยการเรียก
async/awaitโดยตรง แนวคิดที่ว่าตัวแปรแบบนั้นจะยังค้างอยู่ในหน่วยความจำนอกสโคป IIFE ก็แทบจะไม่成立ถ้าใช้
varแบบพร่ำเพรื่อแล้วกำหนดค่าเริ่มต้นตัวแปรนอกสโคป IIFE ก็อาจเห็นค่าที่การเรียก IIFE ครั้งล่าสุดสร้างไว้ได้ต้องปรับแก้นิดหน่อย แต่คุ้มกับความพยายามที่ลงไป
https://github.com/kristopolous/_inject
มันสามารถไล่ดูบริบทของฟังก์ชันแทบใดก็ได้ในช่วงเวลาที่ต้องการเพื่อดูว่าเกิดอะไรขึ้น
วิธีคืออาศัยการใช้ reference counter ในทางที่ผิดเพื่อไม่ให้คอนเท็กซ์ถูกทำลาย
ตอนที่ทำ client-side JS เยอะ ๆ มันมีประโยชน์มาก
เวอร์ชัน killer app ที่ทำสิ่งนี้อย่างสมบูรณ์น่าจะอยู่ในรูปแบบการเปิด REPL ได้จากทุกคอนเท็กซ์
แต่แม้ในสภาพตอนนี้ ถ้าจะใช้งานให้ดีจริง ๆ ก็ต้องชำนาญพอสมควร
https://firefox-source-docs.mozilla.org/devtools-user/debugg...
แก้ไข: เพิ่งสังเกตว่าในบทความที่ลิงก์มาพูดถึงเรื่องนี้เป็นอย่างแรกแบบตรงตัวเลย
[[Scopes]]ดูเหมือน Firefox จะไม่มีวิธีแบบนี้
เพื่อความครบถ้วน ขอแนะนำ Werkzeug
ฉันใช้กับการพัฒนาแบ็กเอนด์ Django และมันมีประโยชน์มาก
มันทำให้สามารถใช้เชลล์ “PDB” ในเบราว์เซอร์ได้ทุกที่ทุกเวลาเมื่อเกิด exception
1/0ตรงจุดที่อยากให้ Werkzeug โผล่ขึ้นมาในเบราว์เซอร์มันเรียบง่ายและตรงไปตรงมามาก
django-extension/runserver_plusอยู่ไหม?เคล็ดลับที่ฉันใช้ประจำคือ ค้นหาสคริปต์จากสตริง UI ที่โหลดมา แล้วค่อยดีบัก
ไปที่แผง Network แล้วเริ่มบันทึกคำขอเครือข่าย เปิดแถบด้านซ้าย จากนั้นค้นหาโค้ดหรือสตริง UI ที่ต้องการ
ปกติมักจะเจอในไฟล์ JS bundle chunk แปลก ๆ แล้วเมื่อคลิกผลลัพธ์ก็จะเปิดคำขอเครือข่ายของไฟล์นั้น
คลิกขวาตรงไหนก็ได้ในไฟล์นั้นแล้วเลือกเมนูประมาณ “Open in Sources” เพื่อกระโดดไปยังดีบักเกอร์
จากนั้นก็วางคำสั่ง
debuggerได้เลย และระหว่างทาง source map ก็น่าจะถูกโหลดด้วยฉันทำงานเป็นโปรแกรมเมอร์ Python/Elixir มานาน และใช้
pdb.set_trace()กับIEx.pry()บ่อยมากไม่นานมานี้ฉันรับช่วงต่อ แบ็กเอนด์ NodeJS ที่ยุ่งเหยิงมากตัวหนึ่ง และกำลังดึงผมที่เหลืออยู่เพราะไม่มีเครื่องมือดีบักที่เหมาะสม
สุดท้ายก็ต้องกลับไปดีบักด้วย
console.logซึ่งให้ความรู้สึกเหมือนมนุษย์ถ้ำไม่น่าเชื่อว่า ecosystem ที่ได้รับความนิยมขนาดนี้จะไม่มี REPL สำหรับดีบักที่ดีพอ มีใครพอบอกได้ไหมว่าควรไปทางไหน?
ใช้
node --inspect-brkแล้วเชื่อมต่อผ่าน VS Code หรือ Chrome DevTools ได้ส่วนที่จุกจิกคือมีเครื่องมือ build อย่างการแปลง TypeScript วางอยู่หน้าคำสั่ง
nodejsหรือไม่ถ้ารัน
nodeตรง ๆ ก็ถือว่าค่อนข้างง่ายREPL สำหรับดีบักก็คือ JavaScript console นั่นเอง
เพิ่มเป็นตัวเลือกดีบักแล้วจะวางเบรกพอยต์และ step เข้าไปในฟังก์ชันได้
เพราะส่วนใหญ่ถูกห่ออยู่ในอ็อบเจ็กต์ JavaScript จึงถือว่าดีบักได้ค่อนข้างดี
--inspectหรือ--inspect-brkใน VSCode ยังใช้คำสั่ง “open JavaScript debug terminal” ได้ด้วย
คำสั่งนี้จะเปิดเทอร์มินัลที่ทำให้คำสั่ง
nodeใด ๆ เริ่มต้นมาพร้อมดีบักเกอร์ที่เชื่อมต่อโดยอัตโนมัติhttps://pypi.org/project/snoop/
เป็น decorator สำหรับการไล่ติดตามแบบลึก
ฉันยังไม่เห็นความสามารถแบบนี้ใน ecosystem ของ Node JS
ในส่วน “Debugging Property Reads” ฉันสงสัยว่าจะใช้ conditional breakpoint เพื่อเปลี่ยน
{configOption: true}ให้เป็น{get configOption() { debugger; return true; }}ได้อย่างไรแค่เขียนทับค่านั้นในคอนโซลให้เป็น getter หรือถ้ามีสิทธิ์เขียนก็แก้ตรงในซอร์สโค้ดได้เลย
อันนี้ดูเหมือนเป็นสิ่งที่ต้องเรียนรู้ให้ได้จริง ๆ แต่อยากรู้ว่ามีหนังสือเฉพาะทางหรือสื่อการเรียนรู้สำหรับมันไหม
หรือว่าทางเดียวคือเจาะลึกการพัฒนาเว็บและฟรอนต์เอนด์แบบไม่สิ้นสุด?
ตอนที่กำลังทำงานอยู่ อาจไม่ค่อยอยากกดลิงก์ไปอ่าน release notes แต่แค่ใช้เวลาไล่ดู 5 นาทีทุกครั้งที่มีเวอร์ชันใหม่ออกมาก็คุ้มแล้ว
ยังมีวิดีโอสั้น ๆ ไม่กี่นาทีที่ดูง่าย เหมาะสำหรับเก็บภาพรวมแบบเร็ว ๆ
แม้จุดประสงค์จะเป็นการแนะนำฟีเจอร์ใหม่ แต่จากประสบการณ์ก็มักช่วยให้เข้าใจข้อจำกัดปัจจุบันของเครื่องมือด้วย