debounce-promise

Wrap any promise-returning function so rapid-fire calls collapse into one execution

Library
npm
v3.1.2
240stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
37/100Needs Attention
Development Activity0
Maintenance20
Community48
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
63/100Good
Architecture65
Code Quality68
Innovation72
Learning Curve45

debounce-promise wraps an async or promise-returning function so that repeated calls within a wait window collapse into a single underlying invocation, while every caller still receives a promise that resolves with the correct result. Unlike traditional debounce utilities built for synchronous callbacks, it understands promises natively, resolving all pending callers together or, in accumulate mode, batching their individual arguments into one call and fanning results back out to each awaiting promise.

It supports a leading-edge mode for immediate first-call execution, a dynamic wait value evaluated on each call, and a small, dependency-free implementation. It is commonly reached for in autocomplete and search-as-you-type inputs, and in any place where multiple concurrent requests for the same resource should be coalesced into one network call or expensive operation.

What You Get

  • A single debounce() function with zero runtime dependencies for wrapping any promise-returning callback
  • Leading-edge invocation option (leading: true) for immediate first-call execution
  • Argument accumulation mode (accumulate: true) that batches all pending calls’ arguments into one invocation and distributes results back individually
  • Support for a dynamic wait value supplied as a function, evaluated on every call

Common Use Cases

  • Debouncing autocomplete/typeahead search-as-you-type requests to a backend or search API
  • Coalescing multiple simultaneous save or update calls into a single API request
  • Batching per-item lookups (e.g. react-select async options) into one bulk request via accumulate mode
  • Rate-limiting expensive computations triggered by rapid UI events such as scroll, resize, or keystrokes

Under The Hood

Architecture The entire library is a single closure-based module (index.js, ~66 lines) with no internal layering: a debounce(fn, wait, options) factory returns a debounced closure that tracks a shared deferred promise, a pending timer, and an array of pending call arguments in its lexical scope, then a private flush() function resolves that deferred once the timer fires by invoking the wrapped fn with either the accumulated argument list or the most recent call’s arguments. There is no dependency injection or configuration beyond the wait/leading/accumulate options, and the only extension point is the wrapped function itself, so the whole behavior is easy to reason about but offers no seams for further customization without editing the source directly.

Tech Stack The package is authored in ES2015 JavaScript and transpiled via Babel (babel-preset-es2015, babel-plugin-transform-async-to-generator) into the published dist/ output referenced by package.json’s main field, with the prepare/postpublish npm-lifecycle scripts (gated by in-publish) driving compile and cleanup only around actual publishes. It declares an empty dependencies object, so it adds no runtime dependencies to consumers; its devDependencies cover the Babel toolchain, rimraf for cleaning dist/, and standard/snazzy for linting.

Code Quality Tests live in test/index.js and use the tap test runner with async/await test bodies (transpiled via a local Babel config), covering leading-edge behavior, accumulate-mode batching and result fan-out, this-context preservation, dynamic wait functions, and promise-rejection propagation through the shared deferred.reject. The npm test script chains the tap suite with standard | snazzy linting, and a .travis.yml wires this into CI, though the badge points at Travis CI, a service the project’s last commit (2023) predates being effectively retired for open source. There are no TypeScript types or type declaration file bundled with the package.

API Design The standout design choice is accumulate mode: rather than simply discarding all but the last call like a conventional debounce, it collects every pending call’s arguments into an array, invokes the wrapped function once with the full batch, and maps each batched result back to the promise its original caller is awaiting by array index. Combined with support for a dynamic wait (a function re-evaluated per call) and a single default export with a two-key options object, the public surface requires almost no boilerplate: existing promise-returning functions can be wrapped in one line with no interface changes required on the caller’s side.

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