Returns a wrapper around a function that enforces concurrency limits. All calls to the wrapper share the same concurrency pool.
Signature
function limit<Args extends unknown[], R>(
fn: (...args: Args) => PromiseLike<R> | R,
concurrency: number,
options?: StandardOptions,
): (...args: Args) => Promise<R>
Parameters
fn
(...args: Args) => PromiseLike<R> | R
required
The function to wrap with concurrency limiting.
Maximum number of concurrent executions allowed.
Limiting options.
Optional AbortSignal to cancel pending operations.
Returns
A wrapped function that enforces the concurrency limit. Returns a promise that resolves with the result of the function.
Throws
AbortError if the signal is aborted while waiting
- Any error thrown by the wrapped function
Examples
Basic concurrency limiting
import { limit } from '@temelj/async';
async function fetchData(id: number) {
const response = await fetch(`/api/data/${id}`);
return response.json();
}
// Limit to 2 concurrent requests
const limitedFetch = limit(fetchData, 2);
// Only 2 requests run at a time
const results = await Promise.all([
limitedFetch(1),
limitedFetch(2),
limitedFetch(3),
limitedFetch(4),
limitedFetch(5),
]);
Database query limiting
import { limit } from '@temelj/async';
async function queryDatabase(sql: string) {
return await db.query(sql);
}
// Limit to 5 concurrent database queries
const limitedQuery = limit(queryDatabase, 5);
const users = await limitedQuery('SELECT * FROM users');
const orders = await limitedQuery('SELECT * FROM orders');
const products = await limitedQuery('SELECT * FROM products');
API rate limiting
import { limit } from '@temelj/async';
const apiCall = limit(
async (endpoint: string) => {
const response = await fetch(`https://api.example.com${endpoint}`);
return response.json();
},
3 // Max 3 concurrent API calls
);
// Process many requests with automatic queuing
const endpoints = Array.from({ length: 20 }, (_, i) => `/data/${i}`);
const results = await Promise.all(endpoints.map(ep => apiCall(ep)));
File processing
import { limit } from '@temelj/async';
import { readFile, writeFile } from 'fs/promises';
const processFile = limit(
async (filePath: string) => {
const content = await readFile(filePath, 'utf-8');
const processed = content.toUpperCase();
await writeFile(filePath + '.processed', processed);
return filePath;
},
4 // Process 4 files at a time
);
const files = [
'file1.txt',
'file2.txt',
'file3.txt',
// ... many more files
];
for (const file of files) {
await processFile(file);
}
Image processing
import { limit } from '@temelj/async';
const processImage = limit(
async (imageUrl: string) => {
const image = await loadImage(imageUrl);
const resized = await resizeImage(image, { width: 800, height: 600 });
const optimized = await optimizeImage(resized);
return optimized;
},
2 // Only process 2 images at a time to save memory
);
const images = await Promise.all(
imageUrls.map(url => processImage(url))
);
With abort signal
import { limit } from '@temelj/async';
const controller = new AbortController();
const limitedTask = limit(
async (n: number) => {
await delay(1000);
return n * 2;
},
2,
{ signal: controller.signal }
);
const tasks = [1, 2, 3, 4, 5].map(n =>
limitedTask(n).catch(error => {
if (error instanceof AbortError) {
console.log(`Task ${n} cancelled`);
return null;
}
throw error;
})
);
// Cancel after 1.5 seconds
setTimeout(() => controller.abort(), 1500);
const results = await Promise.all(tasks);
console.log(results); // Some tasks completed, some cancelled
Batch processing with progress
import { limit } from '@temelj/async';
const processItem = limit(
async (item: string, index: number, total: number) => {
const result = await expensiveOperation(item);
console.log(`Progress: ${index + 1}/${total}`);
return result;
},
3
);
const items = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
const results = await Promise.all(
items.map((item, i) => processItem(item, i, items.length))
);
Resource pool simulation
import { limit } from '@temelj/async';
class ConnectionPool {
private limitedQuery: (sql: string) => Promise<any>;
constructor(maxConnections: number) {
this.limitedQuery = limit(
async (sql: string) => {
// Simulate database query
console.log('Executing:', sql);
await delay(100);
return { rows: [] };
},
maxConnections
);
}
async query(sql: string) {
return this.limitedQuery(sql);
}
}
const pool = new ConnectionPool(5);
// All queries share the same pool of 5 connections
await Promise.all([
pool.query('SELECT * FROM users'),
pool.query('SELECT * FROM orders'),
pool.query('SELECT * FROM products'),
// ... many more queries
]);