Skip to main content

Menu

System onlineAI Tutorials / 2026

AI Tutorials
Knowledge search

Recent · Popular · Tutorials

  • dart3 tutorials
  • java1 tutorial
  • Javascript3 tutorials
  • Node.js Introduction2 tutorials
  • dartdart · General · In depth
  • JavascriptJavascript · Advanced · In depth
  • JavascriptJavascript · Advanced · Mid
  • JavascriptJavascript · Advanced · Short

Find a tutorial

Tell the assistant what you want to learn. It suggests published chapters.

For example: “I want to learn Rust ownership from the start.” The conversation is kept only in this tab.

0 / 2,000 characters

Enter to send, Shift+Enter for a new line. Do not include personal information.

Chapter 3

Modules

This chapter assumes you know closures, prototypes, `this` binding, and promises from earlier chapters. We move fast.
Level: AdvancedLength: Short1 min read

Read at another depth

Modules (and the Road to Runtime Behavior)

This chapter assumes you know closures, prototypes, this binding, and promises from earlier chapters. We move fast.

Trade offs

ES modules (import/export) give static structure: bindings are live links, not copies, and the graph resolves before any code runs.

Code example in javascript
// counter.js
export let count = 0;
export function inc() { count += 1; }
// main.js
import { count, inc } from './counter.js';
inc();
console.log(count); // 1 — live binding, not a snapshot
  • CommonJS (require) copies values and loads synchronously; ES modules are asynchronous and hoisted.
  • Static analysis enables tree-shaking; dynamic import() trades that for lazy loading.
  • Circular imports are legal in ES modules but force careful ordering of initialization.

Failure modes

Code example in javascript
// top-level await blocks the whole module graph downstream
const data = await fetch('/config');
export const ready = data.ok; // every importer waits
  1. Unhandled promise rejections crash Node processes and vanish silently in some browsers — always attach catch or use a global handler.
  2. Microtask starvation: a while loop that queues microtasks (e.g., recursive Promise.resolve().then) starves rendering and timers.
  3. Accidental retained state: a module-level cache keeps every entry alive for the page lifetime; closures over large DOM nodes in long-lived listeners leak memory.

Internals

The event loop drains all microtasks (promise reactions, queueMicrotask) after each macrotask, before the next task. Generators suspend a stack frame without holding the call stack:

Code example in javascript
function* range(n) { for (let i = 0; i < n; i++) yield i; }
const it = range(3);
console.log([...it]); // [0, 1, 2]

Proxy intercepts operations via traps; Reflect exposes the default behavior for forwarding. GC is reachability-based: an unreachable Proxy target is collected even if the proxy is referenced through a weak structure like WeakRef or FinalizationRegistry — but finalizers are not guaranteed to run.

Code example in javascript
const handler = { get(t, k, r) { return Reflect.get(t, k, r) ?? 'default'; } };
const p = new Proxy({}, handler);
console.log(p.missing); // default

Prefer proxies for cross-cutting concerns (validation, logging), not for hiding type mismatches — they add indirection that hurts performance and debuggability.

Exercise

Why does an infinitely recursing then chain freeze the page instead of letting timers fire?

Show answer

Promise reactions are microtasks; the event loop drains every microtask before running the next macrotask (timers, I/O), so a self-perpetuating microtask queue starves them.

Spotted a mistake, or code that does not work?

Report an issue

Chapter: Modules

0 / 2,000 characters

Plain text, for example: the second code sample does not compile. Do not include personal information.

You can't do that