javascript-pro
SKILL.md
JavaScript Pro
Guidelines for modern JavaScript and async programming patterns.
Core Principles
- Async/await over promise chains - Cleaner, more readable code
- Functional patterns - Map, filter, reduce over imperative loops
- Error boundaries - Handle errors at appropriate levels
- Module-first - ES modules with clean exports
- Defensive coding - Nullish coalescing and optional chaining
Modern Syntax (ES2020+)
Nullish Coalescing and Optional Chaining
// Nullish coalescing (??) - only null/undefined
const port = config.port ?? 3000;
// Optional chaining (?.)
const city = user?.address?.city;
const result = obj.method?.();
// Combined pattern
const name = data?.user?.name ?? 'Anonymous';
Destructuring and Spread
// Nested destructuring with defaults
const { user: { name = 'Guest', role = 'viewer' } = {} } = response;
// Rest in destructuring
const { id, ...rest } = obj;
// Spread for immutable updates
const updated = { ...original, status: 'active' };
const combined = [...arr1, ...arr2];
Modern Array Methods
// Array.at() for negative indexing
const last = arr.at(-1);
// Object.fromEntries() for object creation
const obj = Object.fromEntries([['a', 1], ['b', 2]]);
// Array.prototype.flatMap()
const words = sentences.flatMap(s => s.split(' '));
// Object.hasOwn() (safer than hasOwnProperty)
if (Object.hasOwn(obj, 'key')) { }
Async Patterns
Promise Combinators
// Promise.all - fail fast, all must succeed
const [users, posts] = await Promise.all([
fetchUsers(),
fetchPosts()
]);
// Promise.allSettled - get all results regardless of failures
const results = await Promise.allSettled([
riskyOperation1(),
riskyOperation2()
]);
const successes = results.filter(r => r.status === 'fulfilled');
// Promise.race - first to complete wins
const result = await Promise.race([
fetchData(),
timeout(5000)
]);
// Promise.any - first success wins (ignores rejections)
const fastest = await Promise.any([
fetchFromCDN1(),
fetchFromCDN2()
]);
Async Error Handling
// Wrapper for clean try/catch
async function safeAsync(promise) {
try {
const data = await promise;
return [data, null];
} catch (error) {
return [null, error];
}
}
// Usage
const [user, error] = await safeAsync(fetchUser(id));
if (error) {
console.error('Failed to fetch user:', error.message);
return;
}
Async Iteration
// for-await-of for async iterables
async function* paginate(url) {
let nextUrl = url;
while (nextUrl) {
const response = await fetch(nextUrl);
const data = await response.json();
yield data.items;
nextUrl = data.nextPage;
}
}
for await (const page of paginate('/api/items')) {
processItems(page);
}
Controlled Concurrency
async function processWithLimit(items, fn, limit = 5) {
const results = [];
const executing = new Set();
for (const item of items) {
const promise = fn(item).then(result => {
executing.delete(promise);
return result;
});
executing.add(promise);
results.push(promise);
if (executing.size >= limit) {
await Promise.race(executing);
}
}
return Promise.all(results);
}
Module Patterns
Clean Exports
// Named exports for utilities
export function formatDate(date) { }
export function parseDate(str) { }
// Default export for main class/function
export default class ApiClient { }
// Re-exports for barrel files
export { formatDate, parseDate } from './dates.js';
export { default as ApiClient } from './client.js';
Dynamic Imports
// Code splitting with dynamic imports
const module = await import('./heavy-module.js');
// Conditional loading
if (featureEnabled) {
const { Feature } = await import('./feature.js');
new Feature().init();
}
Node.js Patterns
File System (fs/promises)
import { readFile, writeFile, mkdir } from 'fs/promises';
import { existsSync } from 'fs';
async function ensureDir(path) {
if (!existsSync(path)) {
await mkdir(path, { recursive: true });
}
}
const content = await readFile('config.json', 'utf-8');
const config = JSON.parse(content);
Streams
import { createReadStream, createWriteStream } from 'fs';
import { pipeline } from 'stream/promises';
import { createGzip } from 'zlib';
await pipeline(
createReadStream('input.txt'),
createGzip(),
createWriteStream('output.txt.gz')
);
Testing Patterns
import { describe, it, expect, vi } from 'vitest';
describe('UserService', () => {
it('fetches user by id', async () => {
const mockFetch = vi.fn().mockResolvedValue({
json: () => Promise.resolve({ id: 1, name: 'Test' })
});
const user = await fetchUser(1, { fetch: mockFetch });
expect(user.name).toBe('Test');
expect(mockFetch).toHaveBeenCalledWith('/api/users/1');
});
});
Performance Tips
- Use
Map/Setfor frequent lookups (O(1) vs O(n)) - Avoid creating functions in loops
- Use
requestAnimationFramefor DOM updates - Debounce/throttle event handlers
- Prefer
for...ofoverforEachfor break/continue support
Common Anti-Patterns
- Using
==instead of=== - Not handling promise rejections
- Modifying objects during iteration
- Using
varinstead ofconst/let - Callback hell instead of async/await
- Not using optional chaining for nested access
Weekly Installs
3
Repository
arosenkranz/cla…e-configGitHub Stars
1
First Seen
Feb 27, 2026
Security Audits
Installed on
cline3
github-copilot3
codex3
kimi-cli3
gemini-cli3
cursor3