JavaScript Operations

SkillAI & models

JavaScript and Node.js patterns, async programming, modules, runtime internals, and modern ES2024+ features. Use for: javascript, js, node, nodejs, esm, commonjs, promise, async await, event loop, v8, npm, es6, es2024, worker threads, streams, event emitter, prototype, closure.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the JavaScript Operations skill

What this skill tells your AI

The instructions your AI receives, as published by 0xdarkmatter/claude-mods in skills/javascript-ops/SKILL.md and read by ahel’s review.

Comprehensive reference for modern JavaScript and Node.js — async patterns, module systems, runtime internals, and ES2022-2025 features.


Async Decision Tree

What are you doing asynchronously?
│
├─ Simple one-off operation (DB query, HTTP call)
│   └─ async/await with try/catch  ✓ default choice
│
├─ Multiple independent operations
│   ├─ All must succeed → Promise.all([a(), b(), c()])
│   ├─ Don't care about failures → Promise.allSettled([...])
│   └─ First one wins → Promise.race([...]) or Promise.any([...])
│
├─ Need external resolve/reject control (deferred)
│   └─ Promise.withResolvers()  (ES2024)
│
├─ Processing a sequence of async values
│   ├─ Known array → for...of with await inside loop
│   └─ Unknown/infinite sequence → async generator + for await...of
│
├─ Large data / backpressure concerns
│   └─ Streams (ReadableStream / node:stream)
│       ├─ Transform data in flight → TransformStream / Transform
│       └─ Pipe chain → stream.pipeline() (Node) / pipeThrough() (Web)
│
├─ CPU-intensive work (would block event loop)
│   ├─ Short burst → offload with setTimeout(fn, 0) to yield
│   └─ Real work → Worker (browser) / worker_threads (Node)
│       └─ Shared memory needed → SharedArrayBuffer + Atomics
│
└─ Legacy code uses callbacks
    └─ Wrap with util.promisify() (Node) or new Promise() constructor

Module System Decision Tree

Which module system should I use?
│
├─ New project / Node 18+
│   └─ ESM  (set "type": "module" in package.json)
│       ├─ import / export syntax
│       ├─ Top-level await supported
│       └─ Better tree-shaking with bundlers
│
├─ Publishing a library
│   ├─ ESM-only → simplest, but breaks older CJS consumers
│   ├─ CJS-only → safe but no tree-shaking
│   └─ Dual package (recommended) → "exports" field with conditions
│       ├─ "import": "./dist/index.mjs"
│       └─ "require": "./dist/index.cjs"
│
├─ Existing CJS project, want ESM
│   ├─ Per-file migration → rename to .mjs, update require → import
│   ├─ Whole-project → add "type": "module", rename .cjs exceptions
│   └─ Keep CJS, add ESM wrapper → create thin .mjs re-export layer
│
├─ Browser (no bundler)
│   └─ Native ESM — <script type="module"> + importmap
│
└─ Need dynamic loading
    └─ import() — works in both ESM and CJS files
        ├─ Lazy routes / code splitting
        └─ Conditional platform code

Migration path: CJS → Dual → ESM-only


Event Loop Quick Reference

┌─────────────────────────────────────────────────────────┐
│                    Call Stack                           │
│   (synchronous code executes here)                      │
└─────────────────────────┬───────────────────────────────┘
                          │ stack empty?
                          ▼
┌─────────────────────────────────────────────────────────┐
│              Microtask Queue  (drained fully)           │
│   • Promise.then / .catch / .finally callbacks         │
│   • queueMicrotask(fn)                                  │
│   • MutationObserver callbacks (browser)                │
│   • process.nextTick (Node — runs BEFORE other microtasks)│
└─────────────────────────┬───────────────────────────────┘
                          │ microtasks empty?
                          ▼
┌─────────────────────────────────────────────────────────┐
│              Macrotask Queue  (one task per loop tick)  │
│   • setTimeout / setInterval callbacks                  │
│   • setImmediate (Node — runs in "check" phase)         │
│   • I/O callbacks (network, file system)                │
│   • requestAnimationFrame (browser)                     │
│   • MessagePort / Worker messages                       │
└─────────────────────────────────────────────────────────┘

Node.js event loop PHASES (libuv):
  timers → pending callbacks → idle/prepare → poll → check → close callbacks
  └─ process.nextTick + microtasks drain after EVERY phase

Key rules:

  • Microtasks always run before the next macrotask
  • process.nextTick fires before other microtasks (Promise.then)
  • setImmediate fires in the "check" phase, after I/O callbacks
  • setTimeout(fn, 0) fires in "timers" phase — after I/O in same iteration

Modern JS Cheat Sheet (ES2022–2025)

FeatureYearUsage
Array.at(-1)ES2022Last element without .length - 1
Object.hasOwn(obj, key)ES2022Replaces obj.hasOwnProperty(key)
#privateField in classES2022True private (not just convention)
static {} class blockES2022One-time class initialization
Top-level awaitES2022await at module top — ESM only
Error causeES2022new Error('msg', { cause: err })
structuredClone(obj)ES2022Deep clone — built-in, no lodash
Array.findLast()ES2023Find from end
WeakMap(Symbol)ES2023Symbols as WeakMap keys
Object.groupBy(iter, fn)ES2024Group into plain object
Map.groupBy(iter, fn)ES2024Group into Map
Promise.withResolvers()ES2024Deferred pattern
ArrayBuffer.prototype.resize()ES2024Grow/shrink buffer in-place
String.prototype.isWellFormed()ES2024Check valid Unicode
import x from './f.json' with { type: 'json' }ES2024Import attributes (assert {…} is the deprecated legacy syntax)
Set.prototype.union(other)ES2025Set algebra methods
Set.prototype.intersection(other)ES2025Set algebra methods
Set.prototype.difference(other)ES2025Set algebra methods
Iterator helpers (map, filter, take…)ES2025Lazy iterator protocol
using / Symbol.disposeES2025Explicit resource management
Temporal APIStage 3Modern date/time (replaces Date)
import deferStage 3Deferred module evaluation

Node.js Quick Start

// Built-in test runner (Node 18+, stable in Node 20)
import { describe, it, before, after, mock } from 'node:test';
import assert from 'node:assert/strict';

describe('my module', () => {
  it('adds numbers', () => {
    assert.equal(1 + 1, 2);
  });
});

// Run: node --test
// Watch: node --test --watch
// Coverage: node --test --experimental-test-coverage
// fs/promises — built-in, no third-party needed
import { readFile, writeFile, readdir } from 'node:fs/promises';

const content = await readFile('./config.json', 'utf8');
const files = await readdir('./src', { recursive: true }); // Node 18.17+

// .env loading — Node 21+ (no dotenv package required)
// node --env-file=.env server.js

Key built-in modules:

ModulePurpose
node:fs/promisesAsync file system
node:pathPath manipulation
node:urlURL parsing, fileURLToPath
node:cryptoHashing, encryption, UUIDs
node:streamStreams + pipeline()
node:worker_threadsCPU parallelism
node:child_processSubprocess execution
node:testBuilt-in test runner
node:http / node:http2HTTP servers
node:diagnostics_channelObservability hooks
node:perf_hooksPerformance measurement

Error Handling Patterns

// 1. Standard async try/catch
async function fetchUser(id) {
  try {
    const res = await fetch(`/api/users/${id}`);
    if (!res.ok) throw new Error(`HTTP ${res.status}`, { cause: res });
    return await res.json();
  } catch (err) {
    console.error('fetchUser failed:', err);
    throw err; // re-throw unless you can recover
  }
}

// 2. Abort with timeout (Node 17.3+ / browsers)
const signal = AbortSignal.timeout(5000);
const res = await fetch(url, { signal });

// 3. Global unhandled rejection handler
process.on('unhandledRejection', (reason, promise) => {
  console.error('Unhandled rejection:', reason);
  process.exit(1); // always exit — unknown state
});

// 4. AggregateError — wraps multiple errors
const results = await Promise.allSettled([a(), b(), c()]);
const failures = results.filter(r => r.status === 'rejected');
if (failures.length) {
  throw new AggregateError(failures.map(f => f.reason), 'Multiple failures');
}

// 5. Custom Error class
class AppError extends Error {
  constructor(message, { code, cause } = {}) {
    super(message, { cause });
    this.name = 'AppError';
    this.code = code;
  }
}

Common Gotchas

GotchaWhyFix
this is undefined in callbackArrow functions capture this lexically; regular functions don'tUse arrow function or .bind(this)
Closure captures loop variable var ivar is function-scoped; all closures share same iUse let i (block-scoped) or .forEach
== treats null == undefined as trueLoose equality does type coercionAlways use === and !==
0.1 + 0.2 !== 0.3IEEE 754 floating-point precisionMath.round(n * 1e10) / 1e10 or use Number.EPSILON comparison
a?.b ?? c vs a?.b || c?? only falls back on null/undefined; || on any falsyUse ?? when 0 or "" are valid values
typeof null === 'object'Historic JavaScript bugCheck val === null explicitly
[3,10,2].sort()[10,2,3]Default sort converts to stringsProvide comparator: .sort((a,b) => a - b)
parseInt('08') → 8 in modern, 0 in oldOctal parsing in pre-ES5Always pass radix: parseInt(str, 10)
for...in on arraysIterates inherited enumerable properties tooUse for...of or .forEach() for arrays
Promise.all fails fastOne rejection cancels all (others still run)Use Promise.allSettled if you need all results
JSON.stringify drops undefined / functions / SymbolsNot JSON-serializableConvert to null first or use a replacer function
Async function always returns a Promiseasync () => 42 returns Promise<42>, not 42await the call site or chain .then()

Reference Files

FileWhen to Load
references/async-patterns.mdPromise combinators, async iterators, AbortController, Streams, Web Workers, structured concurrency
references/modules-runtime.mdESM/CJS/dual packages, dynamic import, V8 internals, memory management, event loop deep dive
references/modern-features.mdES2022-2025 feature details, Proxy/Reflect, Decorators, Temporal, Explicit Resource Management
references/node-patterns.mdnode:test runner, fs/promises, worker_threads, streams, crypto, graceful shutdown, permission model
references/expert-insights.mdBrowser-side patterns: DOM batching, event delegation, debounce/throttle, memoization, lazy loading, XSS/CSP client security

See Also

  • typescript-ops — TypeScript types, generics, utility types, tsconfig
  • react-ops — React hooks, Server Components, state management
  • vue-ops — Vue 3 Composition API, Pinia, Nuxt
  • testing-ops — Jest, Vitest, Playwright, TDD patterns

Signals

GitHub stars
36
Forks
5
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
javascript-ops
Source
github.com/0xdarkmatter/claude-mods