📘 Blog 8: Debugging and Error Handling in JavaScript: Tools, Techniques, and Best Practices


No matter how experienced a developer you are, bugs are inevitable. Debugging is a core skill that involves identifying, understanding, and resolving problems in your code. Combined with effective error handling, it can drastically improve your development efficiency and the reliability of your applications.

In this eighth blog in the JavaScript Essentials series, we’ll explore how JavaScript handles errors, the most effective debugging techniques, and strategies for writing robust code that fails gracefully when something goes wrong.


1. Types of JavaScript Errors

Understanding error types is the first step to debugging effectively.

SyntaxError

Occurs when code violates JavaScript’s grammar rules.

let x = ; //  SyntaxError

ReferenceError

Accessing a variable that hasn’t been declared.

console.log(a); //  ReferenceError

TypeError

Calling a method on a non-function or accessing a property on undefined or null.

let name = null;
name.toUpperCase(); //  TypeError

RangeError

When a value is not within a valid range (e.g., exceeding call stack).

function recurse() {
  recurse();
}
recurse(); //  RangeError: Maximum call stack size exceeded

URIError, EvalError, AggregateError – less common, but useful to know.


2. The try...catch Block

Use try...catch to handle errors gracefully and avoid crashes.

try {
  let result = riskyFunction();
  console.log(result);
} catch (error) {
  console.error("An error occurred:", error.message);
}

Optional finally block:

Always executes, whether an error occurred or not.

finally {
  console.log("Cleaning up...");
}

3. Throwing Custom Errors

You can throw your own errors for validation or business logic.

function divide(a, b) {
  if (b === 0) {
    throw new Error("Cannot divide by zero");
  }
  return a / b;
}
 
try {
  divide(5, 0);
} catch (e) {
  console.error(e.message);
}

You can also define custom error types:

class ValidationError extends Error {
  constructor(message) {
    super(message);
    this.name = "ValidationError";
  }
}

4. Debugging with Browser Developer Tools

Most browsers (like Chrome, Firefox, Edge) provide powerful DevTools.

Opening DevTools

  • Right-click > Inspect
  • Press F12 or Ctrl+Shift+I

Console Tab

Use for:

  • Logging
  • Testing expressions
  • Viewing error messages

Sources Tab

  • View all loaded scripts
  • Set breakpoints
  • Step through code line by line
  • Watch expressions and variables

5. Using Console Methods

Besides console.log(), use other helpful methods:

console.error("Error message");
console.warn("Warning!");
console.info("Some info");
console.table([{ name: "Alice" }, { name: "Bob" }]);
console.assert(x > 10, "x is not greater than 10");

6. Understanding the Call Stack

The stack trace shows the path the program took before hitting the error.

function a() {
  b();
}
function b() {
  c();
}
function c() {
  throw new Error("Something broke");
}
 
a();

Check the DevTools stack trace to locate the exact function call that caused the issue.


7. Debugging Techniques

Step-by-step Debugging

Use DevTools:

  • Set breakpoints
  • Step over (F10)
  • Step into (F11)
  • Step out (Shift+F11)

Using Watchers

Track variable values as you step through the code.

Conditional Breakpoints

Pause only if a condition is met.

// Right-click a line number > Add Conditional Breakpoint

8. Real Example: Debugging an API Call

async function fetchData() {
  try {
    const res = await fetch('/api/data');
    if (!res.ok) throw new Error("Server error");
    const data = await res.json();
    console.log(data);
  } catch (err) {
    console.error("Failed to fetch:", err);
  }
}

What to check:

  • Is the endpoint correct?
  • Is the network request succeeding?
  • Is the data returned as expected?

9. Handling Async Errors

Async functions must wrap code in try...catch.

async function getUser() {
  try {
    let res = await fetch("/user");
    let user = await res.json();
    return user;
  } catch (e) {
    console.error("Could not fetch user", e);
  }
}

10. Using Linters and Formatters

Linters catch syntax errors and bad practices before runtime.

Popular tools:

  • ESLint
  • Prettier

These tools integrate with most code editors and CI pipelines.


11. Fallbacks and Defensive Programming

Use Optional Chaining

let city = user?.address?.city;

Set Defaults with Nullish Coalescing

let name = user.name ?? "Anonymous";

Sanitize Inputs

function setAge(age) {
  if (typeof age !== "number") throw new TypeError("Age must be a number");
}

12. Logging Best Practices

  • Log meaningful, structured messages
  • Avoid console.log() in production (use logging libraries)
  • Use console.group() and console.time() for performance monitoring

13. Testing Edge Cases

Manually test or write unit tests for:

  • Empty inputs
  • Unexpected values
  • Slow or failed network responses
  • Rapid user interactions (click spamming, form abuse)

14. Common Pitfalls to Avoid

❌ Swallowing errors:

try {
  riskyFunction();
} catch {} // Bad: hides all info

✅ Always handle or log errors meaningfully:

catch (err) {
  console.error("Unexpected error:", err);
}

❌ Blindly using try...catch everywhere
✅ Use only where failure is likely


15. Summary Table

TechniqueUse Case
try...catchCatching runtime errors
DevTools ConsoleTesting and logging
BreakpointsPausing and inspecting live code
console.error, .warnClearer messaging
LintersCatch issues before they run
Optional chaining (?.)Safely access deeply nested properties
Nullish coalescing (??)Provide fallback values

Conclusion

Debugging and error handling are not just about fixing bugs—they’re about writing code that can fail safely and be maintained with confidence. Mastering these tools and techniques will make you a more efficient and reliable JavaScript developer.

In our next blog, we’ll explore building a Dynamic To-Do List App to apply many of the concepts we’ve covered—DOM manipulation, events, arrays, functions, and more.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top