@common.js/p-limit 6.1.0 → 7.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +1 -1
  2. package/index.d.ts +96 -3
  3. package/index.js +74 -36
  4. package/package.json +10 -10
package/README.md CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  The [p-limit](https://www.npmjs.com/package/p-limit) package exported as CommonJS modules.
4
4
 
5
- Exported from [p-limit@6.1.0](https://www.npmjs.com/package/p-limit/v/6.1.0) using https://github.com/etienne-martin/common.js.
5
+ Exported from [p-limit@7.3.0](https://www.npmjs.com/package/p-limit/v/7.3.0) using https://github.com/etienne-martin/common.js.
package/index.d.ts CHANGED
@@ -20,12 +20,34 @@ export type LimitFunction = {
20
20
  This might be useful if you want to teardown the queue at the end of your program's lifecycle or discard any function calls referencing an intermediary state of your app.
21
21
 
22
22
  Note: This does not cancel promises that are already running.
23
+
24
+ When `rejectOnClear` is enabled, pending promises are rejected with an `AbortError`.
25
+ This is recommended if you await the returned promises, for example with `Promise.all`, so pending tasks do not remain unresolved after `clearQueue()`.
23
26
  */
24
27
  clearQueue: () => void;
25
28
 
29
+ /**
30
+ Process an iterable of inputs with limited concurrency.
31
+
32
+ The mapper function receives the item value and its index.
33
+
34
+ This is a convenience function for processing inputs that arrive in batches. For more complex use cases, see [p-map](https://github.com/sindresorhus/p-map).
35
+
36
+ @param iterable - An iterable containing an argument for the given function.
37
+ @param mapperFunction - Promise-returning/async function.
38
+ @returns A promise equivalent to `Promise.all(Array.from(iterable, (item, index) => limit(mapperFunction, item, index)))`.
39
+ */
40
+ map: <Input, ReturnType> (
41
+ iterable: Iterable<Input>,
42
+ mapperFunction: (input: Input, index: number) => PromiseLike<ReturnType> | ReturnType
43
+ ) => Promise<ReturnType[]>;
44
+
26
45
  /**
27
46
  @param fn - Promise-returning/async function.
28
- @param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a lot of functions.
47
+ @param arguments - Any arguments to pass through to `fn`. Support for passing arguments on to the `fn` is provided in order to be able to avoid creating unnecessary closures. You probably don't need this optimization unless you're pushing a *lot* of functions.
48
+
49
+ Warning: Avoid calling the same `limit` function inside a function that is already limited by it. This can create a deadlock where inner tasks never run. Use a separate limiter for inner tasks.
50
+
29
51
  @returns The promise returned by calling `fn(...arguments)`.
30
52
  */
31
53
  <Arguments extends unknown[], ReturnType>(
@@ -37,7 +59,78 @@ export type LimitFunction = {
37
59
  /**
38
60
  Run multiple promise-returning & async functions with limited concurrency.
39
61
 
40
- @param concurrency - Concurrency limit. Minimum: `1`.
62
+ @param concurrency - Concurrency limit. Minimum: `1`. You can pass a number or an options object with a `concurrency` property.
41
63
  @returns A `limit` function.
64
+
65
+ @example
66
+ ```
67
+ import pLimit from 'p-limit';
68
+
69
+ const limit = pLimit(1);
70
+
71
+ const input = [
72
+ limit(() => fetchSomething('foo')),
73
+ limit(() => fetchSomething('bar')),
74
+ limit(() => doSomething())
75
+ ];
76
+
77
+ // Only one promise is run at once
78
+ const result = await Promise.all(input);
79
+ console.log(result);
80
+ ```
81
+
82
+ @example
83
+ ```
84
+ import pLimit from 'p-limit';
85
+
86
+ const limit = pLimit({concurrency: 1});
87
+ ```
88
+ */
89
+ export default function pLimit(concurrency: number | Options): LimitFunction;
90
+
91
+ export type Options = {
92
+ /**
93
+ Concurrency limit.
94
+
95
+ Minimum: `1`.
96
+ */
97
+ readonly concurrency: number;
98
+
99
+ /**
100
+ Reject pending promises with an `AbortError` when `clearQueue()` is called.
101
+
102
+ Default: `false`.
103
+
104
+ This is recommended if you await the returned promises, for example with `Promise.all`, so pending tasks do not remain unresolved after `clearQueue()`.
105
+ */
106
+ readonly rejectOnClear?: boolean;
107
+ };
108
+
109
+ /**
110
+ Returns a function with limited concurrency.
111
+
112
+ The returned function manages its own concurrent executions, allowing you to call it multiple times without exceeding the specified concurrency limit.
113
+
114
+ Ideal for scenarios where you need to control the number of simultaneous executions of a single function, rather than managing concurrency across multiple functions.
115
+
116
+ @param function_ - Promise-returning/async function.
117
+ @return Function with limited concurrency.
118
+
119
+ @example
120
+ ```
121
+ import {limitFunction} from 'p-limit';
122
+
123
+ const limitedFunction = limitFunction(async () => {
124
+ return doSomething();
125
+ }, {concurrency: 1});
126
+
127
+ const input = Array.from({length: 10}, limitedFunction);
128
+
129
+ // Only one promise is run at once.
130
+ await Promise.all(input);
131
+ ```
42
132
  */
43
- export default function pLimit(concurrency: number): LimitFunction;
133
+ export function limitFunction<Arguments extends unknown[], ReturnType>(
134
+ function_: (...arguments_: Arguments) => PromiseLike<ReturnType>,
135
+ options: Options
136
+ ): (...arguments_: Arguments) => Promise<ReturnType>;
package/index.js CHANGED
@@ -2,10 +2,18 @@
2
2
  Object.defineProperty(exports, "__esModule", {
3
3
  value: true
4
4
  });
5
- Object.defineProperty(exports, "default", {
6
- enumerable: true,
7
- get: function() {
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: all[name]
9
+ });
10
+ }
11
+ _export(exports, {
12
+ default: function() {
8
13
  return pLimit;
14
+ },
15
+ limitFunction: function() {
16
+ return limitFunction;
9
17
  }
10
18
  });
11
19
  var _yoctoQueue = /*#__PURE__*/ _interopRequireDefault(require("yocto-queue"));
@@ -164,14 +172,22 @@ var __generator = (void 0) && (void 0).__generator || function(thisArg, body) {
164
172
  }
165
173
  };
166
174
  function pLimit(concurrency) {
175
+ var rejectOnClear = false;
176
+ if (typeof concurrency === "object") {
177
+ var ref, ref1;
178
+ ref = concurrency, concurrency = ref.concurrency, ref1 = ref.rejectOnClear, rejectOnClear = ref1 === void 0 ? false : ref1, ref;
179
+ }
167
180
  validateConcurrency(concurrency);
181
+ if (typeof rejectOnClear !== "boolean") {
182
+ throw new TypeError("Expected `rejectOnClear` to be a boolean");
183
+ }
168
184
  var queue = new _yoctoQueue.default();
169
185
  var activeCount = 0;
170
186
  var resumeNext = function() {
187
+ // Process the next queued function if we're under the concurrency limit
171
188
  if (activeCount < concurrency && queue.size > 0) {
172
- queue.dequeue()();
173
- // Since `pendingCount` has been decreased by one, increase `activeCount` by one.
174
189
  activeCount++;
190
+ queue.dequeue().run();
175
191
  }
176
192
  };
177
193
  var next = function() {
@@ -192,6 +208,7 @@ function pLimit(concurrency) {
192
208
  ];
193
209
  });
194
210
  })();
211
+ // Resolve immediately with the promise (don't wait for completion)
195
212
  resolve(result);
196
213
  _state.label = 1;
197
214
  case 1:
@@ -218,6 +235,7 @@ function pLimit(concurrency) {
218
235
  4
219
236
  ];
220
237
  case 4:
238
+ // Decrement active count and process next queued function
221
239
  next();
222
240
  return [
223
241
  2
@@ -229,42 +247,27 @@ function pLimit(concurrency) {
229
247
  return _ref.apply(this, arguments);
230
248
  };
231
249
  }();
232
- var enqueue = function(function_, resolve, arguments_) {
233
- // Queue `internalResolve` instead of the `run` function
234
- // to preserve asynchronous context.
250
+ var enqueue = function(function_, resolve, reject, arguments_) {
251
+ var queueItem = {
252
+ reject: reject
253
+ };
254
+ // Queue the internal resolve function instead of the run function
255
+ // to preserve the asynchronous execution context.
235
256
  new Promise(function(internalResolve) {
236
- queue.enqueue(internalResolve);
237
- }).then(run.bind(undefined, function_, resolve, arguments_));
238
- _asyncToGenerator(function() {
239
- return __generator(this, function(_state) {
240
- switch(_state.label){
241
- case 0:
242
- // This function needs to wait until the next microtask before comparing
243
- // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously
244
- // after the `internalResolve` function is dequeued and called. The comparison in the if-statement
245
- // needs to happen asynchronously as well to get an up-to-date value for `activeCount`.
246
- return [
247
- 4,
248
- Promise.resolve()
249
- ];
250
- case 1:
251
- _state.sent();
252
- if (activeCount < concurrency) {
253
- resumeNext();
254
- }
255
- return [
256
- 2
257
- ];
258
- }
259
- });
260
- })();
257
+ queueItem.run = internalResolve;
258
+ queue.enqueue(queueItem);
259
+ }).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then
260
+ // Start processing immediately if we haven't reached the concurrency limit
261
+ if (activeCount < concurrency) {
262
+ resumeNext();
263
+ }
261
264
  };
262
265
  var generator = function(function_) {
263
266
  for(var _len = arguments.length, arguments_ = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++){
264
267
  arguments_[_key - 1] = arguments[_key];
265
268
  }
266
- return new Promise(function(resolve) {
267
- enqueue(function_, resolve, arguments_);
269
+ return new Promise(function(resolve, reject) {
270
+ enqueue(function_, resolve, reject, arguments_);
268
271
  });
269
272
  };
270
273
  Object.defineProperties(generator, {
@@ -280,7 +283,14 @@ function pLimit(concurrency) {
280
283
  },
281
284
  clearQueue: {
282
285
  value: function value() {
283
- queue.clear();
286
+ if (!rejectOnClear) {
287
+ queue.clear();
288
+ return;
289
+ }
290
+ var abortError = AbortSignal.abort().reason;
291
+ while(queue.size > 0){
292
+ queue.dequeue().reject(abortError);
293
+ }
284
294
  }
285
295
  },
286
296
  concurrency: {
@@ -297,10 +307,38 @@ function pLimit(concurrency) {
297
307
  }
298
308
  });
299
309
  }
310
+ },
311
+ map: {
312
+ value: function value(iterable, function_) {
313
+ return _asyncToGenerator(function() {
314
+ var _this, promises;
315
+ return __generator(this, function(_state) {
316
+ _this = this;
317
+ promises = Array.from(iterable, function(value, index) {
318
+ return _this(function_, value, index);
319
+ });
320
+ return [
321
+ 2,
322
+ Promise.all(promises)
323
+ ];
324
+ });
325
+ }).apply(this);
326
+ }
300
327
  }
301
328
  });
302
329
  return generator;
303
330
  }
331
+ function limitFunction(function_, options) {
332
+ var limit = pLimit(options);
333
+ return function() {
334
+ for(var _len = arguments.length, arguments_ = new Array(_len), _key = 0; _key < _len; _key++){
335
+ arguments_[_key] = arguments[_key];
336
+ }
337
+ return limit(function() {
338
+ return function_.apply(void 0, _toConsumableArray(arguments_));
339
+ });
340
+ };
341
+ }
304
342
  function validateConcurrency(concurrency) {
305
343
  if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
306
344
  throw new TypeError("Expected `concurrency` to be a number from 1 and up");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@common.js/p-limit",
3
- "version": "6.1.0",
3
+ "version": "7.3.0",
4
4
  "description": "p-limit package exported as CommonJS modules",
5
5
  "license": "MIT",
6
6
  "repository": "etienne-martin/common.js",
@@ -8,28 +8,28 @@
8
8
  "type": "commonjs",
9
9
  "sideEffects": false,
10
10
  "engines": {
11
- "node": ">=18"
11
+ "node": ">=20"
12
12
  },
13
13
  "scripts": {
14
- "test": "xo && ava && tsd"
14
+ "test": "xo && ava && tsd",
15
+ "benchmark": "node benchmark.js"
15
16
  },
16
17
  "files": [
17
18
  "index.js",
18
19
  "index.d.ts"
19
20
  ],
20
21
  "dependencies": {
21
- "@common.js/yocto-queue": "^1.1.1"
22
+ "@common.js/yocto-queue": "^1.2.1"
22
23
  },
23
24
  "devDependencies": {
24
- "ava": "^6.1.3",
25
- "delay": "^6.0.0",
25
+ "ava": "^6.4.1",
26
26
  "in-range": "^3.0.0",
27
27
  "random-int": "^3.0.0",
28
28
  "time-span": "^5.1.0",
29
- "tsd": "^0.31.1",
30
- "xo": "^0.58.0"
29
+ "tsd": "^0.33.0",
30
+ "xo": "^1.2.1"
31
31
  },
32
32
  "homepage": "https://github.com/etienne-martin/common.js#readme",
33
- "types": "./index.d.ts",
34
- "main": "./index.js"
33
+ "main": "./index.js",
34
+ "types": "./index.d.ts"
35
35
  }