p-map
Map over promises concurrently, with controlled concurrency, backpressure, abort signals, and error aggregation.
Repository Health
Technical Analysis
p-map runs an async or sync mapper function over every element of an iterable, awaiting each returned promise while capping how many run at the same time via a concurrency option. It solves the exact gap Promise.all() leaves open: batch operations like paginated API calls, file writes, or database queries need throttling so they don’t overwhelm the target service or run out of memory, but still want to run several in parallel rather than one at a time.
Beyond the core pMap() function, the package exports pMapIterable() for streaming results through an async iterable with independent backpressure control, and pMapSkip — a sentinel a mapper can return to omit an item from the output array without introducing filter-then-map indirection. stopOnError lets callers choose fail-fast semantics or collect every rejection into an AggregateError, and an AbortSignal can cancel in-flight work early. It has no runtime dependencies and ships as a single ESM-only file with full TypeScript types.
What You Get
pMap(input, mapper, options)— awaits every element and mapper result while honoring aconcurrencycap, returning results in original input orderpMapIterable(input, mapper, options)— an async-iterable variant with independentbackpressurecontrol for streaming consumptionpMapSkip— a sentinel value a mapper can return to exclude an item from the result arraystopOnErroroption — choose fail-fast rejection or continue-and-collect into anAggregateErrorsignaloption — cancel in-flight mapping early via a standardAbortController/AbortSignal- Support for both synchronous and asynchronous iterables, including iterables whose items are themselves promises
Common Use Cases
- Fetching or posting to a rate-limited third-party API across a list of IDs without tripping its concurrency or rate limits
- Resizing, uploading, or transforming a batch of files in parallel while capping concurrent file-handle or memory usage
- Running database reads/writes across many rows without exhausting a connection pool
- Streaming large or slow-arriving datasets through
pMapIterableso a consumer can process results as they complete rather than waiting for the whole batch - Filtering a collection while mapping in one pass using
pMapSkip, avoiding a separate.filter()step
Under The Hood
Architecture
p-map exposes three named exports from a single index.js: the promise-returning pMap, the async-generator pMapIterable, and the pMapSkip sentinel symbol. pMap wraps its whole body in a new Promise executor and drives concurrency with a hand-rolled scheduler — a recursive, self-invoking next() that pulls from the shared iterator, launches a detached async IIFE per slot, and decrements/increments a resolvingCount counter to know when the iterable is exhausted and every in-flight mapper has settled. pMapIterable takes a different shape suited to streaming: it keeps a promises array acting as an ordered queue, a trySpawn() function that launches new mapper calls whenever both the concurrency and backpressure ceilings allow it, and yields results by awaiting the head of the queue in a while loop, converting mapper errors into thrown values inside the generator rather than rejecting an unhandled promise. Both paths validate their inputs (iterable-ness, mapper type, integer concurrency) before doing any work, and pMap wires an AbortSignal listener with an explicit cleanup() step so the listener doesn’t leak past resolution.
Tech Stack
The package is pure, dependency-free ES2022+ JavaScript distributed as native ESM ("type": "module", exports.default) with hand-written index.d.ts type declarations rather than generated ones, targeting Node.js 18+ per engines. There is no build step — index.js ships as-authored. Tooling is entirely dev-side: xo (an opinionated ESLint config) for linting, ava as the test runner, and tsd for asserting the .d.ts file’s type signatures compile and infer correctly, all wired through a single npm test script and a GitHub Actions workflow.
Code Quality
test.js is extensive — several hundred lines covering concurrency ordering, stopOnError true/false branches, AggregateError shape, abort-signal cancellation, pMapSkip (including multiple skips in one run), and both sync and async iterables, using ava with delay/time-span/random-int helpers to assert timing-sensitive concurrency behavior rather than just final output. A separate test-multiple-pmapskips-performance.js guards against an accidental quadratic path when many skips occur. Error handling is explicit throughout — thrown TypeErrors for invalid input shapes, careful distinction between stopOnError: true (immediate reject) and false (collect into AggregateError) — and the .d.ts file’s inferred types are checked at build time via tsd, giving the library both automated type-safety and behavioral test coverage despite its small surface area.
What Makes It Unique
p-map’s distinguishing choice is offering two complementary concurrency models rather than one: a batch-oriented pMap that resolves to a single ordered array, and a separately-tunable pMapIterable whose backpressure option decouples “how many mappers run at once” from “how many completed-but-unconsumed results may pile up” — letting a slow consumer avoid runaway memory growth from a fast producer. Combined with pMapSkip for inline filtering and native AbortSignal support, it covers concurrency-control patterns that competing single-function libraries typically split across several packages, while still shipping as one small, dependency-free file.
Used by 16 apps in this directory
Bun
Developer Tools
An all-in-one JavaScript and TypeScript toolkit — one Rust-and-JavaScriptCore binary that replaces Node.js, npm, a bundler, and a test runner with faster equivalents.
Documenso
Digital Signiture
Self-hosted, open-source DocuSign alternative with legally binding PDF signatures, multi-party workflows, and a full REST and tRPC API.
Kibana
Analytics · Monitoring
Your open source window into the Elastic Stack — query, visualize, and act on data stored in Elasticsearch with real-time dashboards, AI-assisted search, and automated alerting.
Laudspeaker
Marketing · Automation
Open-source customer engagement platform for building visual, event-triggered messaging journeys across email, SMS, push, in-app, and webhooks.
LobeHub
AI Assistants · Productivity · Automation
Your Chief Agent Operator — build, schedule, and collaborate with an entire AI team in one self-hostable workspace.
Logto
Authentication
Open-source auth infrastructure for SaaS and AI apps with OIDC, SAML, and RBAC
Mastra Code
AI Code Assistants
"A coding agent that never compacts" — a terminal-based AI coding agent built on the Mastra framework, with Observational Memory instead of context compaction, multi-model support, and OAuth login for Claude Max or ChatGPT Plus.
openclaude
AI Agents · AI Code Assistants
Run Claude Code workflows against any LLM — OpenAI, Gemini, Ollama, and 200+ backends — from a single terminal-first CLI.
overleaf
Collaboration · Productivity
Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.