1 | # p-queue [![Build Status](https://travis-ci.org/sindresorhus/p-queue.svg?branch=master)](https://travis-ci.org/sindresorhus/p-queue) [![codecov](https://codecov.io/gh/sindresorhus/p-queue/branch/master/graph/badge.svg)](https://codecov.io/gh/sindresorhus/p-queue)
|
2 |
|
3 | > Promise queue with concurrency control
|
4 |
|
5 | Useful for rate-limiting async (or sync) operations. For example, when interacting with a REST API or when doing CPU/memory intensive tasks.
|
6 |
|
7 |
|
8 | ## Install
|
9 |
|
10 | ```
|
11 | $ npm install p-queue
|
12 | ```
|
13 |
|
14 |
|
15 | ## Usage
|
16 |
|
17 | Here we run only one promise at the time. For example, set `concurrency` to 4 to run four promises at the same time.
|
18 |
|
19 | ```js
|
20 | const {default: PQueue} = require('p-queue');
|
21 | const got = require('got');
|
22 |
|
23 | const queue = new PQueue({concurrency: 1});
|
24 |
|
25 | (async () => {
|
26 | await queue.add(() => got('sindresorhus.com'));
|
27 | console.log('Done: sindresorhus.com');
|
28 | })();
|
29 |
|
30 | (async () => {
|
31 | await queue.add(() => got('ava.li'));
|
32 | console.log('Done: ava.li');
|
33 | })();
|
34 |
|
35 | (async () => {
|
36 | const task = await getUnicornTask();
|
37 | await queue.add(task);
|
38 | console.log('Done: Unicorn task');
|
39 | })();
|
40 | ```
|
41 |
|
42 |
|
43 | ## API
|
44 |
|
45 | ### PQueue(options?)
|
46 |
|
47 | Returns a new `queue` instance, which is an [`EventEmitter3`](https://github.com/primus/eventemitter3) subclass.
|
48 |
|
49 | #### options
|
50 |
|
51 | Type: `object`
|
52 |
|
53 | ##### concurrency
|
54 |
|
55 | Type: `number`\
|
56 | Default: `Infinity`\
|
57 | Minimum: `1`
|
58 |
|
59 | Concurrency limit.
|
60 |
|
61 | ##### timeout
|
62 |
|
63 | Type: `number`
|
64 |
|
65 | Per-operation timeout in milliseconds. Operations fulfill once `timeout` elapses if they haven't already.
|
66 |
|
67 | ##### throwOnTimeout
|
68 |
|
69 | Type: `boolean`\
|
70 | Default: `false`
|
71 |
|
72 | Whether or not a timeout is considered an exception.
|
73 |
|
74 | ##### autoStart
|
75 |
|
76 | Type: `boolean`\
|
77 | Default: `true`
|
78 |
|
79 | Whether queue tasks within concurrency limit, are auto-executed as soon as they're added.
|
80 |
|
81 | ##### queueClass
|
82 |
|
83 | Type: `Function`
|
84 |
|
85 | Class with a `enqueue` and `dequeue` method, and a `size` getter. See the [Custom QueueClass](#custom-queueclass) section.
|
86 |
|
87 | ##### intervalCap
|
88 |
|
89 | Type: `number`\
|
90 | Default: `Infinity`\
|
91 | Minimum: `1`
|
92 |
|
93 | The max number of runs in the given interval of time.
|
94 |
|
95 | ##### interval
|
96 |
|
97 | Type: `number`\
|
98 | Default: `0`\
|
99 | Minimum: `0`
|
100 |
|
101 | The length of time in milliseconds before the interval count resets. Must be finite.
|
102 |
|
103 | ##### carryoverConcurrencyCount
|
104 |
|
105 | Type: `boolean`\
|
106 | Default: `false`
|
107 |
|
108 | Whether the task must finish in the given interval or will be carried over into the next interval count.
|
109 |
|
110 | ### queue
|
111 |
|
112 | `PQueue` instance.
|
113 |
|
114 | #### .add(fn, options?)
|
115 |
|
116 | Adds a sync or async task to the queue. Always returns a promise.
|
117 |
|
118 | ##### fn
|
119 |
|
120 | Type: `Function`
|
121 |
|
122 | Promise-returning/async function.
|
123 |
|
124 | #### options
|
125 |
|
126 | Type: `object`
|
127 |
|
128 | ##### priority
|
129 |
|
130 | Type: `number`\
|
131 | Default: `0`
|
132 |
|
133 | Priority of operation. Operations with greater priority will be scheduled first.
|
134 |
|
135 | #### .addAll(fns, options?)
|
136 |
|
137 | Same as `.add()`, but accepts an array of sync or async functions and returns a promise that resolves when all functions are resolved.
|
138 |
|
139 | #### .pause()
|
140 |
|
141 | Put queue execution on hold.
|
142 |
|
143 | #### .start()
|
144 |
|
145 | Start (or resume) executing enqueued tasks within concurrency limit. No need to call this if queue is not paused (via `options.autoStart = false` or by `.pause()` method.)
|
146 |
|
147 | Returns `this` (the instance).
|
148 |
|
149 | #### .onEmpty()
|
150 |
|
151 | Returns a promise that settles when the queue becomes empty.
|
152 |
|
153 | Can be called multiple times. Useful if you for example add additional items at a later time.
|
154 |
|
155 | #### .onIdle()
|
156 |
|
157 | Returns a promise that settles when the queue becomes empty, and all promises have completed; `queue.size === 0 && queue.pending === 0`.
|
158 |
|
159 | The difference with `.onEmpty` is that `.onIdle` guarantees that all work from the queue has finished. `.onEmpty` merely signals that the queue is empty, but it could mean that some promises haven't completed yet.
|
160 |
|
161 | #### .clear()
|
162 |
|
163 | Clear the queue.
|
164 |
|
165 | #### .size
|
166 |
|
167 | Size of the queue.
|
168 |
|
169 |
|
170 | #### .sizeBy(options)
|
171 |
|
172 | Size of the queue, filtered by the given options.
|
173 |
|
174 | For example, this can be used to find the number of items remaining in the queue with a specific priority level.
|
175 |
|
176 | ```js
|
177 | const queue = new PQueue();
|
178 |
|
179 | queue.add(async () => 'π¦', {priority: 1});
|
180 | queue.add(async () => 'π¦', {priority: 0});
|
181 | queue.add(async () => 'π¦', {priority: 1});
|
182 |
|
183 | console.log(queue.sizeBy({priority: 1}));
|
184 | //=> 2
|
185 |
|
186 | console.log(queue.sizeBy({priority: 0}));
|
187 | //=> 1
|
188 | ```
|
189 |
|
190 | #### .pending
|
191 |
|
192 | Number of pending promises.
|
193 |
|
194 | #### [.timeout](#timeout)
|
195 |
|
196 | #### [.concurrency](#concurrency)
|
197 |
|
198 | #### .isPaused
|
199 |
|
200 | Whether the queue is currently paused.
|
201 |
|
202 |
|
203 | ## Events
|
204 |
|
205 | #### active
|
206 |
|
207 | Emitted as each item is processed in the queue for the purpose of tracking progress.
|
208 |
|
209 | ```js
|
210 | const delay = require('delay');
|
211 | const {default: PQueue} = require('p-queue');
|
212 |
|
213 | const queue = new PQueue({concurrency: 2});
|
214 |
|
215 | let count = 0;
|
216 | queue.on('active', () => {
|
217 | console.log(`Working on item #${++count}. Size: ${queue.size} Pending: ${queue.pending}`);
|
218 | });
|
219 |
|
220 | queue.add(() => Promise.resolve());
|
221 | queue.add(() => delay(2000));
|
222 | queue.add(() => Promise.resolve());
|
223 | queue.add(() => Promise.resolve());
|
224 | queue.add(() => delay(500));
|
225 | ```
|
226 |
|
227 |
|
228 | ## Advanced example
|
229 |
|
230 | A more advanced example to help you understand the flow.
|
231 |
|
232 | ```js
|
233 | const delay = require('delay');
|
234 | const {default: PQueue} = require('p-queue');
|
235 |
|
236 | const queue = new PQueue({concurrency: 1});
|
237 |
|
238 | (async () => {
|
239 | await delay(200);
|
240 |
|
241 | console.log(`8. Pending promises: ${queue.pending}`);
|
242 | //=> '8. Pending promises: 0'
|
243 |
|
244 | (async () => {
|
245 | await queue.add(async () => 'π');
|
246 | console.log('11. Resolved')
|
247 | })();
|
248 |
|
249 | console.log('9. Added π');
|
250 |
|
251 | console.log(`10. Pending promises: ${queue.pending}`);
|
252 | //=> '10. Pending promises: 1'
|
253 |
|
254 | await queue.onIdle();
|
255 | console.log('12. All work is done');
|
256 | })();
|
257 |
|
258 | (async () => {
|
259 | await queue.add(async () => 'π¦');
|
260 | console.log('5. Resolved')
|
261 | })();
|
262 | console.log('1. Added π¦');
|
263 |
|
264 | (async () => {
|
265 | await queue.add(async () => 'π΄');
|
266 | console.log('6. Resolved')
|
267 | })();
|
268 | console.log('2. Added π΄');
|
269 |
|
270 | (async () => {
|
271 | await queue.onEmpty();
|
272 | console.log('7. Queue is empty');
|
273 | })();
|
274 |
|
275 | console.log(`3. Queue size: ${queue.size}`);
|
276 | //=> '3. Queue size: 1`
|
277 |
|
278 | console.log(`4. Pending promises: ${queue.pending}`);
|
279 | //=> '4. Pending promises: 1'
|
280 | ```
|
281 |
|
282 | ```
|
283 | $ node example.js
|
284 | 1. Added π¦
|
285 | 2. Added π΄
|
286 | 3. Queue size: 1
|
287 | 4. Pending promises: 1
|
288 | 5. Resolved π¦
|
289 | 6. Resolved π΄
|
290 | 7. Queue is empty
|
291 | 8. Pending promises: 0
|
292 | 9. Added π
|
293 | 10. Pending promises: 1
|
294 | 11. Resolved π
|
295 | 12. All work is done
|
296 | ```
|
297 |
|
298 |
|
299 | ## Custom QueueClass
|
300 |
|
301 | For implementing more complex scheduling policies, you can provide a QueueClass in the options:
|
302 |
|
303 | ```js
|
304 | class QueueClass {
|
305 | constructor() {
|
306 | this._queue = [];
|
307 | }
|
308 |
|
309 | enqueue(run, options) {
|
310 | this._queue.push(run);
|
311 | }
|
312 |
|
313 | dequeue() {
|
314 | return this._queue.shift();
|
315 | }
|
316 |
|
317 | get size() {
|
318 | return this._queue.length;
|
319 | }
|
320 |
|
321 | filter(options) {
|
322 | return this._queue;
|
323 | }
|
324 | }
|
325 | ```
|
326 |
|
327 | `p-queue` will call corresponding methods to put and get operations from this queue.
|
328 |
|
329 |
|
330 | ## Related
|
331 |
|
332 | - [p-limit](https://github.com/sindresorhus/p-limit) - Run multiple promise-returning & async functions with limited concurrency
|
333 | - [p-throttle](https://github.com/sindresorhus/p-throttle) - Throttle promise-returning & async functions
|
334 | - [p-debounce](https://github.com/sindresorhus/p-debounce) - Debounce promise-returning & async functions
|
335 | - [p-all](https://github.com/sindresorhus/p-all) - Run promise-returning & async functions concurrently with optional limited concurrency
|
336 | - [Moreβ¦](https://github.com/sindresorhus/promise-fun)
|
337 |
|
338 |
|
339 | ---
|
340 |
|
341 | <div align="center">
|
342 | <b>
|
343 | <a href="https://tidelift.com/subscription/pkg/npm-p-queue?utm_source=npm-p-queue&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
344 | </b>
|
345 | <br>
|
346 | <sub>
|
347 | Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
348 | </sub>
|
349 | </div>
|