paralysis 1.0.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.
package/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) Gabriel de Oliveira <gabrielhk3@gmail.com> (https://nocnitsa.com)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Paralysis
2
+
3
+ Maps over promises concurrently.
4
+
5
+ ```js
6
+ import parallel from "paralysis";
7
+
8
+ async function getUser(id) {
9
+ const response = await fetch(
10
+ `https://jsonplaceholder.typicode.com/users/${id}`,
11
+ );
12
+ const user = await response.json();
13
+ return user;
14
+ }
15
+
16
+ const users = await parallel([1, 2, 3, 4, 5], getUser, 2);
17
+ ```
18
+
19
+ This is similar to
20
+ [`Promise.all()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all),
21
+ but accepts an optional concurrency limit.
package/dist/index.cjs ADDED
@@ -0,0 +1,41 @@
1
+ 'use strict';
2
+
3
+ var TinyQueue = require('tinyqueue');
4
+
5
+ function createRun(concurrency) {
6
+ const queue = new TinyQueue();
7
+ let slots = Math.floor(concurrency);
8
+ function release() {
9
+ const next = queue.pop();
10
+ if (next) {
11
+ const [resolve, delayed] = next;
12
+ resolve(delayed);
13
+ } else {
14
+ slots++;
15
+ }
16
+ }
17
+ function runRecipe([fn, args]) {
18
+ return new Promise((resolve) => {
19
+ resolve(fn(...args));
20
+ }).finally(release);
21
+ }
22
+ return function run(recipe) {
23
+ if (slots > 0) {
24
+ slots--;
25
+ return runRecipe(recipe);
26
+ }
27
+ return new Promise((resolve) => {
28
+ queue.push([resolve, recipe]);
29
+ }).then(runRecipe);
30
+ };
31
+ }
32
+ function holdback(list, fn, concurrency = Infinity) {
33
+ if (!(typeof concurrency === "number" && concurrency >= 1)) {
34
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
35
+ }
36
+ const run = createRun(concurrency);
37
+ return Promise.all(Array.from(list, (...args) => run([fn, args])));
38
+ }
39
+
40
+ module.exports = holdback;
41
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/holdback.js"],"sourcesContent":["import TinyQueue from \"tinyqueue\";\n\nfunction createRun(concurrency) {\n const queue = new TinyQueue();\n let slots = Math.floor(concurrency);\n\n function release() {\n // Check if we have more functions waiting in the queue. If we\n // do, run the next delayed function. Otherwise, free a slot.\n const next = queue.pop();\n if (next) {\n const [resolve, delayed] = next;\n resolve(delayed);\n } else {\n slots++;\n }\n }\n\n function runRecipe([fn, args]) {\n return new Promise((resolve) => {\n resolve(fn(...args));\n }).finally(release);\n }\n\n return function run(recipe) {\n // If we have an available slot, take the slot and return\n // a promise that executes the function immediately.\n if (slots > 0) {\n slots--;\n return runRecipe(recipe);\n }\n\n // If the limit of slots is reached, enqueue the function\n // and return a promise that will be resolved only after\n // the next slot is released and the function is executed.\n return new Promise((resolve) => {\n queue.push([resolve, recipe]);\n }).then(runRecipe);\n };\n}\n\nexport function holdback(list, fn, concurrency = Infinity) {\n if (!(typeof concurrency === \"number\" && concurrency >= 1)) {\n throw new TypeError(\"Expected `concurrency` to be a number from 1 and up\");\n }\n const run = createRun(concurrency);\n return Promise.all(Array.from(list, (...args) => run([fn, args])));\n}\n"],"names":[],"mappings":";;;;AAEA,SAAS,UAAU,WAAA,EAAa;AAC9B,EAAA,MAAM,KAAA,GAAQ,IAAI,SAAA,EAAU;AAC5B,EAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA;AAElC,EAAA,SAAS,OAAA,GAAU;AAGjB,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,EAAI;AACvB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,CAAC,OAAA,EAAS,OAAO,CAAA,GAAI,IAAA;AAC3B,MAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,KAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAAS,SAAA,CAAU,CAAC,EAAA,EAAI,IAAI,CAAA,EAAG;AAC7B,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,OAAA,CAAQ,EAAA,CAAG,GAAG,IAAI,CAAC,CAAA;AAAA,IACrB,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAAA,EACpB;AAEA,EAAA,OAAO,SAAS,IAAI,MAAA,EAAQ;AAG1B,IAAA,IAAI,QAAQ,CAAA,EAAG;AACb,MAAA,KAAA,EAAA;AACA,MAAA,OAAO,UAAU,MAAM,CAAA;AAAA,IACzB;AAKA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,KAAA,CAAM,IAAA,CAAK,CAAC,OAAA,EAAS,MAAM,CAAC,CAAA;AAAA,IAC9B,CAAC,CAAA,CAAE,IAAA,CAAK,SAAS,CAAA;AAAA,EACnB,CAAA;AACF;AAEO,SAAS,QAAA,CAAS,IAAA,EAAM,EAAA,EAAI,WAAA,GAAc,QAAA,EAAU;AACzD,EAAA,IAAI,EAAE,OAAO,WAAA,KAAgB,QAAA,IAAY,eAAe,CAAA,CAAA,EAAI;AAC1D,IAAA,MAAM,IAAI,UAAU,qDAAqD,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,GAAA,GAAM,UAAU,WAAW,CAAA;AACjC,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,IAAA,EAAM,CAAA,GAAI,IAAA,KAAS,GAAA,CAAI,CAAC,EAAA,EAAI,IAAI,CAAC,CAAC,CAAC,CAAA;AACnE;;;;"}
@@ -0,0 +1,35 @@
1
+ type Promisable<T> = T | PromiseLike<T>;
2
+
3
+ /**
4
+ * Maps the async function `fn` over each element of
5
+ * `list`, limited by `concurrency` executions in parallel.
6
+ * Returns a promise that resolves with all the results.
7
+ *
8
+ * @example
9
+ * ```js
10
+ * import holdback from "holdback";
11
+ *
12
+ * async function getUser(id) {
13
+ * const response = await fetch(
14
+ * `https://jsonplaceholder.typicode.com/users/${id}`,
15
+ * );
16
+ * const user = await response.json();
17
+ * return user;
18
+ * }
19
+ *
20
+ * const users = await holdback([1, 2, 3, 4, 5], getUser, 2);
21
+ * ```
22
+ *
23
+ * @param list List that is iterated over concurrently, calling `fn` for each item.
24
+ * @param fn Async function that is called for every item of `list`.
25
+ * @param concurrency Number of concurrently pending promises returned by `fn`.
26
+ * @returns A new promise.
27
+ */
28
+ declare function holdback<T, U>(
29
+ list: ArrayLike<T>,
30
+ fn: (element: T, index: number) => Promisable<U>,
31
+ concurrency?: number,
32
+ ): Promise<Array<U>>;
33
+
34
+ export { holdback as default };
35
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","sources":["../src/index.d.ts"],"mappings":"AAAA,KAAK,UAAU,UAAU,WAAW;;AAEpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;iBACwB,QAAQ;AAChC,QAAQ,SAAS;AACjB,qCAAqC,UAAU;AAC/C;AACA,GAAG,OAAO,CAAC,KAAK;;;;","names":[]}
@@ -0,0 +1,35 @@
1
+ type Promisable<T> = T | PromiseLike<T>;
2
+
3
+ /**
4
+ * Maps the async function `fn` over each element of
5
+ * `list`, limited by `concurrency` executions in parallel.
6
+ * Returns a promise that resolves with all the results.
7
+ *
8
+ * @example
9
+ * ```js
10
+ * import holdback from "holdback";
11
+ *
12
+ * async function getUser(id) {
13
+ * const response = await fetch(
14
+ * `https://jsonplaceholder.typicode.com/users/${id}`,
15
+ * );
16
+ * const user = await response.json();
17
+ * return user;
18
+ * }
19
+ *
20
+ * const users = await holdback([1, 2, 3, 4, 5], getUser, 2);
21
+ * ```
22
+ *
23
+ * @param list List that is iterated over concurrently, calling `fn` for each item.
24
+ * @param fn Async function that is called for every item of `list`.
25
+ * @param concurrency Number of concurrently pending promises returned by `fn`.
26
+ * @returns A new promise.
27
+ */
28
+ declare function holdback<T, U>(
29
+ list: ArrayLike<T>,
30
+ fn: (element: T, index: number) => Promisable<U>,
31
+ concurrency?: number,
32
+ ): Promise<Array<U>>;
33
+
34
+ export { holdback as default };
35
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","sources":["../src/index.d.ts"],"mappings":"AAAA,KAAK,UAAU,UAAU,WAAW;;AAEpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;iBACwB,QAAQ;AAChC,QAAQ,SAAS;AACjB,qCAAqC,UAAU;AAC/C;AACA,GAAG,OAAO,CAAC,KAAK;;;;","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,39 @@
1
+ import TinyQueue from 'tinyqueue';
2
+
3
+ function createRun(concurrency) {
4
+ const queue = new TinyQueue();
5
+ let slots = Math.floor(concurrency);
6
+ function release() {
7
+ const next = queue.pop();
8
+ if (next) {
9
+ const [resolve, delayed] = next;
10
+ resolve(delayed);
11
+ } else {
12
+ slots++;
13
+ }
14
+ }
15
+ function runRecipe([fn, args]) {
16
+ return new Promise((resolve) => {
17
+ resolve(fn(...args));
18
+ }).finally(release);
19
+ }
20
+ return function run(recipe) {
21
+ if (slots > 0) {
22
+ slots--;
23
+ return runRecipe(recipe);
24
+ }
25
+ return new Promise((resolve) => {
26
+ queue.push([resolve, recipe]);
27
+ }).then(runRecipe);
28
+ };
29
+ }
30
+ function holdback(list, fn, concurrency = Infinity) {
31
+ if (!(typeof concurrency === "number" && concurrency >= 1)) {
32
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
33
+ }
34
+ const run = createRun(concurrency);
35
+ return Promise.all(Array.from(list, (...args) => run([fn, args])));
36
+ }
37
+
38
+ export { holdback as default };
39
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/holdback.js"],"sourcesContent":["import TinyQueue from \"tinyqueue\";\n\nfunction createRun(concurrency) {\n const queue = new TinyQueue();\n let slots = Math.floor(concurrency);\n\n function release() {\n // Check if we have more functions waiting in the queue. If we\n // do, run the next delayed function. Otherwise, free a slot.\n const next = queue.pop();\n if (next) {\n const [resolve, delayed] = next;\n resolve(delayed);\n } else {\n slots++;\n }\n }\n\n function runRecipe([fn, args]) {\n return new Promise((resolve) => {\n resolve(fn(...args));\n }).finally(release);\n }\n\n return function run(recipe) {\n // If we have an available slot, take the slot and return\n // a promise that executes the function immediately.\n if (slots > 0) {\n slots--;\n return runRecipe(recipe);\n }\n\n // If the limit of slots is reached, enqueue the function\n // and return a promise that will be resolved only after\n // the next slot is released and the function is executed.\n return new Promise((resolve) => {\n queue.push([resolve, recipe]);\n }).then(runRecipe);\n };\n}\n\nexport function holdback(list, fn, concurrency = Infinity) {\n if (!(typeof concurrency === \"number\" && concurrency >= 1)) {\n throw new TypeError(\"Expected `concurrency` to be a number from 1 and up\");\n }\n const run = createRun(concurrency);\n return Promise.all(Array.from(list, (...args) => run([fn, args])));\n}\n"],"names":[],"mappings":";;AAEA,SAAS,UAAU,WAAA,EAAa;AAC9B,EAAA,MAAM,KAAA,GAAQ,IAAI,SAAA,EAAU;AAC5B,EAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,WAAW,CAAA;AAElC,EAAA,SAAS,OAAA,GAAU;AAGjB,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,EAAI;AACvB,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,MAAM,CAAC,OAAA,EAAS,OAAO,CAAA,GAAI,IAAA;AAC3B,MAAA,OAAA,CAAQ,OAAO,CAAA;AAAA,IACjB,CAAA,MAAO;AACL,MAAA,KAAA,EAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,SAAS,SAAA,CAAU,CAAC,EAAA,EAAI,IAAI,CAAA,EAAG;AAC7B,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,OAAA,CAAQ,EAAA,CAAG,GAAG,IAAI,CAAC,CAAA;AAAA,IACrB,CAAC,CAAA,CAAE,OAAA,CAAQ,OAAO,CAAA;AAAA,EACpB;AAEA,EAAA,OAAO,SAAS,IAAI,MAAA,EAAQ;AAG1B,IAAA,IAAI,QAAQ,CAAA,EAAG;AACb,MAAA,KAAA,EAAA;AACA,MAAA,OAAO,UAAU,MAAM,CAAA;AAAA,IACzB;AAKA,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY;AAC9B,MAAA,KAAA,CAAM,IAAA,CAAK,CAAC,OAAA,EAAS,MAAM,CAAC,CAAA;AAAA,IAC9B,CAAC,CAAA,CAAE,IAAA,CAAK,SAAS,CAAA;AAAA,EACnB,CAAA;AACF;AAEO,SAAS,QAAA,CAAS,IAAA,EAAM,EAAA,EAAI,WAAA,GAAc,QAAA,EAAU;AACzD,EAAA,IAAI,EAAE,OAAO,WAAA,KAAgB,QAAA,IAAY,eAAe,CAAA,CAAA,EAAI;AAC1D,IAAA,MAAM,IAAI,UAAU,qDAAqD,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,GAAA,GAAM,UAAU,WAAW,CAAA;AACjC,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,IAAA,EAAM,CAAA,GAAI,IAAA,KAAS,GAAA,CAAI,CAAC,EAAA,EAAI,IAAI,CAAC,CAAC,CAAC,CAAA;AACnE;;;;"}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "paralysis",
3
+ "version": "1.0.0",
4
+ "description": "Map over promises concurrently",
5
+ "repository": "th3rius/paralysis",
6
+ "keywords": [
7
+ "async",
8
+ "concurrency",
9
+ "parallel",
10
+ "limit",
11
+ "queue",
12
+ "throttle",
13
+ "promise"
14
+ ],
15
+ "author": "Gabriel de Oliveira <gabrielhk3@gmail.com> (https://nocnitsa.com)",
16
+ "license": "MIT",
17
+ "type": "module",
18
+ "scripts": {
19
+ "prepare": "husky",
20
+ "build": "rimraf dist && pkgroll --sourcemap",
21
+ "test": "node --test --experimental-test-module-mocks **/*.spec.js"
22
+ },
23
+ "main": "./dist/index.cjs",
24
+ "module": "./dist/index.mjs",
25
+ "types": "./dist/index.d.cts",
26
+ "exports": {
27
+ "require": {
28
+ "types": "./dist/index.d.cts",
29
+ "default": "./dist/index.cjs"
30
+ },
31
+ "import": {
32
+ "types": "./dist/index.d.mts",
33
+ "default": "./dist/index.mjs"
34
+ }
35
+ },
36
+ "dependencies": {
37
+ "tinyqueue": "^2.0.3"
38
+ },
39
+ "devDependencies": {
40
+ "@faker-js/faker": "^10.2.0",
41
+ "husky": "^9.1.7",
42
+ "pkgroll": "^2.21.5",
43
+ "prettier": "^3.8.1",
44
+ "rimraf": "^6.1.2",
45
+ "typescript": "^5.9.3"
46
+ }
47
+ }
package/src/index.js ADDED
@@ -0,0 +1,2 @@
1
+ import { paralysis } from "./paralysis.js";
2
+ export default paralysis;
@@ -0,0 +1,48 @@
1
+ import TinyQueue from "tinyqueue";
2
+
3
+ function createRun(concurrency) {
4
+ const queue = new TinyQueue();
5
+ let slots = Math.floor(concurrency);
6
+
7
+ function release() {
8
+ // Check if we have more functions waiting in the queue. If we
9
+ // do, run the next delayed function. Otherwise, free a slot.
10
+ const next = queue.pop();
11
+ if (next) {
12
+ const [resolve, delayed] = next;
13
+ resolve(delayed);
14
+ } else {
15
+ slots++;
16
+ }
17
+ }
18
+
19
+ function runRecipe([fn, args]) {
20
+ return new Promise((resolve) => {
21
+ resolve(fn(...args));
22
+ }).finally(release);
23
+ }
24
+
25
+ return function run(recipe) {
26
+ // If we have an available slot, take the slot and return
27
+ // a promise that executes the function immediately.
28
+ if (slots > 0) {
29
+ slots--;
30
+ return runRecipe(recipe);
31
+ }
32
+
33
+ // If the limit of slots is reached, enqueue the function
34
+ // and return a promise that will be resolved only after
35
+ // the next slot is released and the function is executed.
36
+ return new Promise((resolve) => {
37
+ queue.push([resolve, recipe]);
38
+ }).then(runRecipe);
39
+ };
40
+ }
41
+
42
+ export function paralysis(list, fn, concurrency = Infinity) {
43
+ if (!(typeof concurrency === "number" && concurrency >= 1)) {
44
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
45
+ }
46
+ const run = createRun(concurrency);
47
+ return Promise.all(Array.from(list, (...args) => run([fn, args])));
48
+ }