SmartCodingTips

๐Ÿข Debugging Asynchronous JavaScript

Asynchronous code (like setTimeout, fetch, or async/await) can be tricky to debug because it doesn't execute in a predictable top-down order.

๐Ÿ“ 1. Understand the Call Stack and Event Loop

Async functions are scheduled via the event loop. Use the Call Stack, Event Queue, and Network tabs in DevTools to observe when callbacks run.

๐Ÿ›‘ 2. Use async/await for Cleaner Debugging

Instead of chaining .then(), use async/await to keep your code linear and easier to step through.

async function fetchData() {
  try {
    const res = await fetch('https://api.example.com/data');
    const data = await res.json();
    console.log(data); // Easier to log and trace
  } catch (err) {
    console.error('Error:', err);
  }
}
fetchData();

๐Ÿž 3. Set Breakpoints Inside Async Functions

In browser DevTools, set breakpoints inside async functions or inside .then() blocks to pause execution at the right moment.

๐Ÿ” 4. Use console.trace() in Callbacks

This prints the stack trace to show where the callback originated from:

setTimeout(() => {
  console.trace("Inside timeout");
}, 1000);

๐Ÿ•ต๏ธ 5. Watch Promise States

In Chrome DevTools, go to the Sources tab โ†’ Async Call Stack section to track unresolved promises or pending async calls.

๐Ÿงช 6. Use Network Tab for Async HTTP Calls

If you're debugging fetch() or AJAX, use the Network tab to check status codes, payloads, and response bodies.

๐Ÿงฐ Bonus Tips

  • Temporarily slow network (set to โ€œSlow 3Gโ€) in DevTools to test delays
  • Use await new Promise(resolve => setTimeout(resolve, 1000)) to simulate waiting
  • Log before and after async calls to trace execution flow
  • Use linters to catch unhandled promises or missing await
๐Ÿ’ก Tip: Always handle errors in async code with try...catch to avoid silent failures.