p-map

Map over promises concurrently, with controlled concurrency, backpressure, abort signals, and error aggregation.

Library
npm
v7.0.7
1,510stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
65/100Good
Development Activity64
Maintenance44
Community52
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
80/100Excellent
Architecture80
Code Quality88
Innovation62
Learning Curve90

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 a concurrency cap, returning results in original input order
  • pMapIterable(input, mapper, options) — an async-iterable variant with independent backpressure control for streaming consumption
  • pMapSkip — a sentinel value a mapper can return to exclude an item from the result array
  • stopOnError option — choose fail-fast rejection or continue-and-collect into an AggregateError
  • signal option — cancel in-flight mapping early via a standard AbortController/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 pMapIterable so 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

Rust
67%
MIT

Bun

Developer Tools

95,895

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.

View details
92
Repo Health
91
Technical
64
Dependency
Built with
Rust67%
C++19%
Updated yesterday
TypeScript
92%
AGPL 3.0

Documenso

Digital Signiture

14,913

Self-hosted, open-source DocuSign alternative with legally binding PDF signatures, multi-party workflows, and a full REST and tRPC API.

View details
93
Repo Health
79
Technical
71
Dependency
Built with
TypeScript92%
Updated today
TypeScript
98%
Other

Kibana

Analytics · Monitoring

21,284

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.

View details
98
Repo Health
87
Technical
66
Dependency
Built with
TypeScript98%
Updated yesterday
TypeScript
94%
AGPL 3.0

Laudspeaker

Marketing · Automation

2,620

Open-source customer engagement platform for building visual, event-triggered messaging journeys across email, SMS, push, in-app, and webhooks.

View details
51
Repo Health
66
Technical
62
Dependency
Built with
TypeScript94%
Updated 1 months ago
TypeScript
99%
Other

LobeHub

AI Assistants · Productivity · Automation

82,273

Your Chief Agent Operator — build, schedule, and collaborate with an entire AI team in one self-hostable workspace.

View details
92
Repo Health
81
Technical
69
Dependency
Built with
TypeScript99%
Updated today
TypeScript
97%
MPL 2.0

Logto

Authentication

14,510

Open-source auth infrastructure for SaaS and AI apps with OIDC, SAML, and RBAC

View details
91
Repo Health
83
Technical
63
Dependency
Built with
TypeScript97%
Updated yesterday
TypeScript
99%
Apache 2.0

Mastra Code

AI Code Assistants

27,743

"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.

View details
88
Repo Health
73
Technical
65
Dependency
Built with
TypeScript99%
Updated today
TypeScript
99%
Other

openclaude

AI Agents · AI Code Assistants

32,842

Run Claude Code workflows against any LLM — OpenAI, Gemini, Ollama, and 200+ backends — from a single terminal-first CLI.

View details
85
Repo Health
78
Technical
78
Dependency
Built with
TypeScript99%
Updated yesterday
JavaScript
63%
AGPL 3.0

overleaf

Collaboration · Productivity

18,090

Open-source, real-time collaborative LaTeX editor with sandboxed compilation and full TeXLive support for self-hosted academic and research teams.

View details
82
Repo Health
80
Technical
62
Dependency
Built with
JavaScript63%
TypeScript29%
Updated 1 months ago

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search