Skip to content
JavaScript Modules & Error Handling Explained — Complete Code Organization Guide

JavaScript Modules & Error Handling Explained — Complete Code Organization Guide

DodaTech Updated Jun 6, 2026 7 min read

As JavaScript applications grow, you need to organize code into separate files (modules) and handle errors gracefully — modules keep code maintainable, error handling keeps it reliable.

What You’ll Learn

  • Named exports vs default exports
  • Importing modules — named, default, namespace, dynamic imports
  • How modules differ from regular scripts (strict mode, scoping)
  • Try/catch/finally for error handling
  • Custom error classes and error types
  • Debugging with console methods and breakpoints

Why Modules & Error Handling Matter

Without modules, all your code lives in one giant file — impossible to navigate, test, or maintain. Without error handling, one bad API response can crash the entire application. The Doda Browser uses modules to organize extension APIs, bookmark management, and settings into separate files. The Durga Antivirus Pro dashboard uses try/catch to handle network failures gracefully, showing “Connection lost” instead of a white screen.

Learning Path

    flowchart LR
  A[JavaScript Functions] --> B[DOM & Async JS]
  B --> C[Modules & Error Handling]
  C --> D[Advanced JS]
  C --> E[React / Frameworks]
  C --> F[You Are Here]
  
Prerequisites: You should understand JavaScript, JavaScript, and how to use basic JavaScript.

What Are Modules?

A module is a JavaScript file that exports values (variables, functions, classes) so other files can import them. Think of a module like a library bookshelf — each shelf (module) has specific books (exports), and you borrow what you need.

Exporting

// utils/math.js

// Named exports — export multiple values
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export class Calculator { }

// Rename on export
function subtract(a, b) { return a - b; }
export { subtract as sub };

Default Export

Each module can have ONE default export:

// utils/logger.js
export default function log(message) {
  console.log(`[LOG] ${message}`);
}

Importing

// Import named exports
import { PI, add, Calculator } from './utils/math.js';

// Rename imports
import { add as sum } from './utils/math.js';

// Import everything as a namespace
import * as MathUtils from './utils/math.js';
MathUtils.add(2, 3);

// Import default
import log from './utils/logger.js';

// Default + named together
import Logger, { LogLevel } from './utils/logger.js';

Line by line:

  • import { PI, add } from './utils/math.js' — Import specific named exports using destructuring-like syntax
  • import * as MathUtils from './utils/math.js' — Import everything into a single object
  • import log from './utils/logger.js' — Import the default export (no curly braces)

Dynamic Imports

Static imports always load at page load. Dynamic imports load on demand — useful for code splitting:

// Static — must be at top level
import { format } from './formatter.js';

// Dynamic — anywhere in code
async function loadFormatter() {
  if (condition) {
    const module = await import('./formatter.js');
    module.format(data);
  }
}

When to use dynamic imports: Large libraries (charts, editors), rarely-used features, and sections loaded on user interaction. This is critical for keeping initial page load fast in Doda Browser extensions.

Module Features

  • Modules always use strict mode automatically
  • Each module has its own scope — no global variable pollution
  • Modules are deferred by default (<script type="module">)
  • Modules are cached after first load
  • Static imports are hoisted (evaluated before the module body)

Error Handling

Try / Catch / Finally

try {
  // Code that might fail
  const data = JSON.parse(userInput);
  process(data);
} catch (error) {
  // Handle the error
  console.error('Operation failed:', error.message);
} finally {
  // Always runs — cleanup code
  cleanup();
}

Line by line:

  • try — Wrap code that might throw an error
  • catch (error) — If an error is thrown, execution jumps here. error is the Error object with .message and .name properties
  • finally — Runs regardless of success or failure. Used for cleanup (closing files, hiding spinners)

Throwing Errors

function divide(a, b) {
  if (b === 0) {
    throw new Error('Division by zero');
  }
  if (typeof a !== 'number' || typeof b !== 'number') {
    throw new TypeError('Both arguments must be numbers');
  }
  return a / b;
}

Custom Error Classes

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

try {
  throw new ValidationError('Email is required', 'email');
} catch (e) {
  if (e instanceof ValidationError) {
    console.log(`Field ${e.field}: ${e.message}`);
  }
}

Debugging with DevTools

// Console methods
console.log('Info');         // General output
console.error('Error');      // Red message
console.warn('Warning');     // Yellow message
console.table([{a: 1}]);    // Tabular display

// Timing
console.time('label');
// ... code to measure ...
console.timeEnd('label');    // Shows elapsed time

// Stack trace
console.trace('Where was I called?');

// Breakpoints
debugger;  // Pauses execution in DevTools

Common Mistakes

1. Forgetting type="module" in HTML

<script src="app.js"></script>  <!-- import/export will throw SyntaxError -->
<script type="module" src="app.js"></script>  <!-- correct -->

2. Mixing default and named imports incorrectly

// If module exports: export default function log() { }
import log from './logger.js';        // Correct
import { log } from './logger.js';     // Wrong — named export doesn't exist

3. Not catching promise rejections in async functions

async function load() {
  const data = await fetch('/api/data');  // Rejection is unhandled
}

4. Catching errors too broadly

try {
  userInput.toUpperCase();  // TypeError if input is null
} catch (e) {
  // Catches everything — including bugs you should fix
}

Let programming errors crash (they indicate bugs). Catch operational errors.

5. Using relative paths incorrectly

import { x } from 'utils';   // Looks in node_modules
import { x } from './utils';  // Looks relative to current file

Practice Questions

  1. What’s the difference between static and dynamic imports? Static imports are evaluated at load time, must be at top level, and are hoisted. Dynamic imports (import()) return a Promise and enable code splitting.

  2. What’s the difference between named and default exports? A module can have multiple named exports but only one default export. Named imports use {}, default imports don’t.

  3. What does finally guarantee in try/catch? The finally block always runs, regardless of whether an error was thrown or caught.

  4. What’s the difference between throw and return? throw stops execution and passes control to the nearest catch. return exits the function normally.

Challenge: Create a module validator.js that exports a validateEmail(email) function and a default validatePassword(password) function. Import both in a main file and test them.

FAQ

What is the difference between static and dynamic imports?
Static imports (import ... from ...) are evaluated at load time, must be at the top level, and are hoisted. Dynamic imports (import()) are functions that return a Promise, can be called anywhere, and enable code splitting.
What is the difference between throw and return?
throw stops execution and passes control to the nearest catch block. return exits the function normally.
Should I use try/catch for every async call?
For top-level async code, yes. For functions that return promises, let the caller handle errors.
What is the error object’s stack property?
A string with the call stack at the point where the error was thrown — useful for debugging.
Can I import CSS or JSON as a module?
Yes — CSS modules and JSON modules are supported in modern browsers for type="module" scripts.
What is the difference between a module and a regular script?
Modules have their own scope (no global variables), are deferred by default, and support import/export. Regular scripts execute globally and synchronously.

Try It Yourself

Since modules require a server to work, here’s a self-contained example with error handling:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Error Handling Playground</title>
  <style>
    body { font-family: Arial, sans-serif; padding: 2rem; }
    pre { background: #f4f4f4; padding: 1rem; border-radius: 5px; }
    input { padding: 0.5rem; margin-right: 0.5rem; }
  </style>
</head>
<body>
  <h1>Error Handling Sandbox</h1>
  <input type="text" id="jsonInput" value='{"name":"Alice"}' placeholder="Enter JSON">
  <button id="btnParse">Parse JSON</button>
  <pre id="output"></pre>

  <script>
    const out = document.getElementById('output');

    document.getElementById('btnParse').addEventListener('click', () => {
      const input = document.getElementById('jsonInput').value;
      out.textContent = '';

      try {
        const data = JSON.parse(input);
        out.textContent = `Success! Name: ${data.name}`;
      } catch (error) {
        out.textContent = `Error: ${error.message}`;
      } finally {
        out.textContent += '\n(Parse attempt completed)';
      }
    });
  </script>
</body>
</html>

What’s Next

Now that you understand modules and error handling, explore advanced JavaScript:

LessonDescription
JavaScript HomeBack to the JavaScript hub
https://tutorials.dodatech.com/programming-languages/javascript/js-advanced/Advanced JavaScript — RegExp, Proxy, performance
https://tutorials.dodatech.com/programming-languages/javascript/js-async/Async JavaScript — more on promises
https://tutorials.dodatech.com/programming-languages/javascript/js-dom/DOM & Browser APIs
React ComponentsBuild React apps using ES modules

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

What’s Next

Congratulations on completing this Js Modules tutorial! Here’s where to go from here:

  • Practice daily — Consistency is more important than long study sessions
  • Build a project — Apply what you learned by building something real
  • Explore related topics — Check out other tutorials in the same category
  • Join the community — Discuss with other learners and share your progress

Remember: every expert was once a beginner. Keep coding!

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro