JavaScript Modules & Error Handling Explained — Complete Code Organization Guide
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]
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 syntaximport * as MathUtils from './utils/math.js'— Import everything into a single objectimport 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 errorcatch (error)— If an error is thrown, execution jumps here.erroris the Error object with.messageand.namepropertiesfinally— 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
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.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.What does
finallyguarantee in try/catch? Thefinallyblock always runs, regardless of whether an error was thrown or caught.What’s the difference between
throwandreturn?throwstops execution and passes control to the nearestcatch.returnexits 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
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:
| Lesson | Description |
|---|---|
| JavaScript Home | Back 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 Components | Build 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