Show me how the concurrency limiter actually queues tasks.
Show me how the concurrency limiter actually queues tasks.
About sindresorhus/p-limit · 2 messages · last activity 7/13/2026
The concurrency limiter queues tasks through a two-stage promise mechanism in the enqueue function [index.js:L46-L57].
How it works:
-
Queue Creation: A
Queueobject stores pending tasks [index.js:L14]. -
Enqueue Process: When you call
limit(fn), it creates a new Promise that wraps the queuing logic [index.js:L60-L62]:const enqueue = (function_, resolve, reject, arguments_) => { const queueItem = {reject}; new Promise(internalResolve => { queueItem.run = internalResolve; queue.enqueue(queueItem); }).then(run.bind(undefined, function_, resolve, arguments_));The key insight: instead of queueing the
runfunction directly, it queues a resolver callback (internalResolve). This preserves the async execution context. -
Concurrency Check: If we haven't hit the concurrency limit,
resumeNext()is called immediately [index.js:L55-L57]:if (activeCount < concurrency) { resumeNext(); } -
Dequeue & Execute:
resumeNext()checks if there's capacity and space, then dequeues the item and callsrun()[index.js:L17-L22]:const resumeNext = () => { if (activeCount < concurrency && queue.size > 0) { activeCount++; queue.dequeue().run(); // Calls internalResolve, triggering .then(run...) } }; -
Task Completion: After the task finishes,
next()decrementsactiveCountand processes the next queued task [index.js:L24-L27].
The queue is passive—tasks don't execute until resumeNext() resolves them.
FOLLOW_UPS:
- What does the Queue data structure look like?
- How does activeCount and pendingCount get exposed?
- What happens when clearQueue is called?
Want to ask your own question?
Open chat for sindresorhus/p-limitPublic Q&A. Generated by RepoPilot from the actual source of sindresorhus/p-limit. AI answers can be incomplete or stale — verify before relying on them.