typescriptintermediate
Promise Concurrency Patterns
Master Promise.all, allSettled, race, any — parallel execution with error handling and timeouts.
typescriptPress ⌘/Ctrl + Shift + C to copy
// Simulate async operations
const fetchUser = (id: number) =>
new Promise<string>((resolve, reject) =>
setTimeout(() => {
if (id > 0) resolve(`User-${id}`);
else reject(new Error(`Invalid id: ${id}`));
}, Math.random() * 200)
);
// Promise.all — fail fast (all or nothing)
async function fetchAllUsers(ids: number[]) {
try {
const users = await Promise.all(ids.map(fetchUser));
console.log('All users:', users);
} catch (e) {
console.error('One failed, all rejected:', (e as Error).message);
}
}
// Promise.allSettled — never throws, get all results
async function fetchUsersSettled(ids: number[]) {
const results = await Promise.allSettled(ids.map(fetchUser));
const succeeded = results
.filter((r): r is PromiseFulfilledResult<string> => r.status === 'fulfilled')
.map((r) => r.value);
const failed = results
.filter((r): r is PromiseRejectedResult => r.status === 'rejected')
.map((r) => r.reason.message);
console.log('Succeeded:', succeeded);
console.log('Failed:', failed);
}
// Promise.race — first to settle wins
async function withTimeout<T>(promise: Promise<T>, ms: number): Promise<T> {
const timeout = new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error(`Timeout after ${ms}ms`)), ms)
);
return Promise.race([promise, timeout]);
}
// Promise.any — first to succeed wins (ignores rejections)
async function fetchFromFastestMirror() {
const mirrors = [
fetchUser(1), // fast
fetchUser(2), // medium
fetchUser(3), // slow
];
try {
const fastest = await Promise.any(mirrors);
console.log('Fastest:', fastest);
} catch (e) {
console.error('All failed:', (e as AggregateError).errors);
}
}
// Concurrency limiter
async function pMap<T, R>(
items: T[],
fn: (item: T) => Promise<R>,
concurrency: number
): Promise<R[]> {
const results: R[] = [];
let index = 0;
async function worker() {
while (index < items.length) {
const i = index++;
results[i] = await fn(items[i]);
}
}
const workers = Array.from(
{ length: Math.min(concurrency, items.length) },
() => worker()
);
await Promise.all(workers);
return results;
}
// Usage
await fetchAllUsers([1, 2, 3]);
await fetchUsersSettled([1, -1, 3]);
await fetchFromFastestMirror();
// Limited concurrency: 3 at a time
const ids = Array.from({ length: 10 }, (_, i) => i + 1);
const results = await pMap(ids, fetchUser, 3);
console.log('pMap results:', results);
// Timeout
try {
await withTimeout(fetchUser(1), 50);
} catch (e) {
console.log('Timed out:', (e as Error).message);
}Use Cases
- Parallel API calls with error handling
- Timeout and race conditions
- Controlled concurrency
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
typescriptadvanced
Node.js In-Memory Task Queue
A simple in-memory task queue with concurrency control, retries, and priority support.
Best for: Rate-limited API call processing
#nodejs#queue
typescriptintermediate
Semaphore for Concurrency Limiting
Control concurrent async operations with a semaphore pattern: rate limiting, connection pooling, and batch processing.
Best for: API rate limiting
#nodejs#concurrency
typescriptintermediate
Promise Pool for Batch Processing
Process large arrays with controlled concurrency using a promise pool pattern with progress tracking.
Best for: Bulk API requests
#nodejs#promise
typescriptintermediate
Event Loop and Timers
Understand Node.js event loop phases with setTimeout, setInterval, setImmediate, and process.nextTick.
Best for: Understanding async execution order
#nodejs#event-loop