p-map

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

Library
npm
v7.0.8
1,513 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
70 /100 Good
Development Activity 72
Maintenance 56
Community 52
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
80 /100 Excellent
Architecture 80
Code Quality 88
Innovation 62
Learning Curve 90

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 17 apps in this directory

Rust
67%
MIT

Bun

Developer Tools

96,068

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
Rust 67%
C++ 19%
TypeScript 10%
Updated 6 days ago
TypeScript
92%
AGPL 3.0

Documenso

Digital Signiture

15,224

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
68
Dependency
Built with
TypeScript 92%
Updated 5 days ago
TypeScript
98%
Other

Kibana

Analytics · Monitoring

21,301

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
63
Dependency
Built with
TypeScript 98%
Updated 5 days ago
TypeScript
94%
AGPL 3.0

Laudspeaker

Automation · Marketing

2,626

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
TypeScript 94%
Updated 2 months ago
TypeScript
99%
Other

LobeHub

AI Assistants · Automation · Productivity

82,864

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
66
Dependency
Built with
TypeScript 99%
Updated 5 days ago
TypeScript
97%
MPL 2.0

Logto

Authentication

14,639

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

View details
92
Repo Health
83
Technical
64
Dependency
Built with
TypeScript 97%
Updated 5 days ago
TypeScript
99%
Apache 2.0

Mastra Code

AI Code Assistants

28,378

"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
90
Repo Health
73
Technical
65
Dependency
Built with
TypeScript 99%
Updated 5 days ago
TypeScript
99%
Other

openclaude

AI Agents · AI Code Assistants

33,554

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
71
Dependency
Built with
TypeScript 99%
Updated 1 weeks ago
TypeScript
91%
MIT

OpenClaw

AI Agents · AI Assistants

390,670

An open-source AI assistant that runs on your own hardware and meets you in Discord, Slack, WhatsApp, iMessage, Telegram, and 20+ other channels, with native apps for every major platform.

View details
88
Repo Health
88
Technical
68
Dependency
Built with
TypeScript 91%
Updated 5 days 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