@altano/tiny-async-pool 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-MIT +23 -0
- package/README.md +87 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +33 -0
- package/package.json +67 -0
package/LICENSE-MIT
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Copyright (c) 2017 Rafael Xavier de Souza http://rafael.xavier.blog.br
|
|
2
|
+
Copyright (c) 2022 Alan Norbauer https://alan.norbauer.com
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person
|
|
5
|
+
obtaining a copy of this software and associated documentation
|
|
6
|
+
files (the "Software"), to deal in the Software without
|
|
7
|
+
restriction, including without limitation the rights to use,
|
|
8
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the
|
|
10
|
+
Software is furnished to do so, subject to the following
|
|
11
|
+
conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
18
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
20
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
21
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
22
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
23
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# tiny-async-pool
|
|
2
|
+
|
|
3
|
+
## Why?
|
|
4
|
+
|
|
5
|
+
The goal of this library is to use the native async iterator (ES9), native async functions, and native Promise to implement concurrent/batched work.
|
|
6
|
+
|
|
7
|
+
## What?
|
|
8
|
+
|
|
9
|
+
`doWorkAndYield` runs multiple promise-returning & async functions in a limited concurrency pool. It rejects immediately as soon as one of the promises rejects. It calls the iterator function as soon as possible (under concurrency limit). It returns an async iterator that yields as soon as a promise completes (under concurrency limit). For example:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const timeout = (ms) =>
|
|
13
|
+
new Promise((resolve) => setTimeout(() => resolve(ms), ms));
|
|
14
|
+
|
|
15
|
+
for await (const ms of doWorkAndYield(2, [1000, 5000, 3000, 2000], timeout)) {
|
|
16
|
+
console.log(ms);
|
|
17
|
+
}
|
|
18
|
+
// Call iterator timeout(1000)
|
|
19
|
+
// Call iterator timeout(5000)
|
|
20
|
+
// Concurrency limit of 2 reached, wait for the quicker one to complete...
|
|
21
|
+
// 1000 finishes
|
|
22
|
+
// for await...of outputs "1000"
|
|
23
|
+
// Call iterator timeout(3000)
|
|
24
|
+
// Concurrency limit of 2 reached, wait for the quicker one to complete...
|
|
25
|
+
// 3000 finishes
|
|
26
|
+
// for await...of outputs "3000"
|
|
27
|
+
// Call iterator timeout(2000)
|
|
28
|
+
// Itaration is complete, wait until running ones complete...
|
|
29
|
+
// 5000 finishes
|
|
30
|
+
// for await...of outputs "5000"
|
|
31
|
+
// 2000 finishes
|
|
32
|
+
// for await...of outputs "2000"
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
$ npm install @altano/tiny-async-pool
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import { doWorkAndYield } from "@altano/tiny-async-pool";
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### ES9 for await...of
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
for await (const value of doWorkAndYield(concurrency, iterable, iteratorFn)) {
|
|
49
|
+
console.log(value);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API
|
|
54
|
+
|
|
55
|
+
### `doWorkAndYield(concurrency, iterable, iteratorFn)`
|
|
56
|
+
|
|
57
|
+
Runs multiple promise-returning & async functions in a limited concurrency pool. It rejects immediately as soon as one of the promises rejects. It calls the iterator function as soon as possible (under concurrency limit). It returns an async iterator that yields as soon as a promise completes (under concurrency limit).
|
|
58
|
+
|
|
59
|
+
#### concurrency
|
|
60
|
+
|
|
61
|
+
The concurrency limit number (>= 1).
|
|
62
|
+
|
|
63
|
+
#### iterable
|
|
64
|
+
|
|
65
|
+
An input [iterable object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterable_protocol), such as [`String`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), [`TypedArray`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray), [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map), and [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set).
|
|
66
|
+
|
|
67
|
+
#### iteratorFn
|
|
68
|
+
|
|
69
|
+
Iterator function that takes two arguments: the value of each iteration and the iterable object itself. The iterator function should either return a promise or be an async function.
|
|
70
|
+
|
|
71
|
+
### `doWork(concurrency, iterable, iteratorFn)`
|
|
72
|
+
|
|
73
|
+
The same as `doWorkAndYield(...)` but just returns a Promise that resolves when all work resolves/rejects, e.g.:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const timeout = (ms) =>
|
|
77
|
+
new Promise((resolve) => setTimeout(() => resolve(ms), ms));
|
|
78
|
+
|
|
79
|
+
await doWork(2, [1000, 5000, 3000, 2000], timeout);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
This project is a fork of `async-pool` by Rafael Xavier de Souza. It modernizes (as of 2022) the library by being a first-class TypeScript and ESM module.
|
|
85
|
+
|
|
86
|
+
MIT © [Rafael Xavier de Souza](http://rafael.xavier.blog.br)
|
|
87
|
+
MIT © [Alan Norbauer](https://alan.norbauer.com)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
declare type IterableItem<T> = T extends Iterable<infer R> ? R : never;
|
|
2
|
+
/**
|
|
3
|
+
* Process items from `iterable` in batches and yield the result of each call to
|
|
4
|
+
* `iteratorFn`
|
|
5
|
+
*/
|
|
6
|
+
declare function doWorkAndYield<TIn, TOut, TIterable extends Iterable<TIn>>(
|
|
7
|
+
/**
|
|
8
|
+
* The size of the batch of work, or, how many times `iteratorFn` will be
|
|
9
|
+
* called in parallel.
|
|
10
|
+
*/
|
|
11
|
+
concurrentCount: number,
|
|
12
|
+
/**
|
|
13
|
+
* An iterable that contains the items that should be passed to `iteratorFn`.
|
|
14
|
+
*/
|
|
15
|
+
iterable: TIterable,
|
|
16
|
+
/**
|
|
17
|
+
* The async callback function that does the work. Will be passed items from
|
|
18
|
+
* `iterable`.
|
|
19
|
+
*/
|
|
20
|
+
iteratorFn: (item: IterableItem<TIterable>, Iterable: TIterable) => Promise<TOut>): AsyncGenerator<Awaited<TOut>, void, unknown>;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Process items from `iterable` in batches.
|
|
24
|
+
*/
|
|
25
|
+
declare function doWork<TIn, TOut, TIterable extends Iterable<TIn>>(...args: Parameters<typeof doWorkAndYield<TIn, TOut, TIterable>>): Promise<void>;
|
|
26
|
+
|
|
27
|
+
export { doWork, doWorkAndYield };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// src/doWorkAndYield.ts
|
|
2
|
+
async function* doWorkAndYield(concurrentCount, iterable, iteratorFn) {
|
|
3
|
+
const executing = /* @__PURE__ */ new Set();
|
|
4
|
+
async function consume() {
|
|
5
|
+
const [promise, value] = await Promise.race(executing);
|
|
6
|
+
executing.delete(promise);
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
for (const item of iterable) {
|
|
10
|
+
const result = iteratorFn(item, iterable);
|
|
11
|
+
const promise = result.then((value) => [
|
|
12
|
+
promise,
|
|
13
|
+
value
|
|
14
|
+
]);
|
|
15
|
+
executing.add(promise);
|
|
16
|
+
if (executing.size >= concurrentCount) {
|
|
17
|
+
yield await consume();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
while (executing.size) {
|
|
21
|
+
yield await consume();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/doWork.ts
|
|
26
|
+
async function doWork(...args) {
|
|
27
|
+
for await (const _result of doWorkAndYield(...args)) {
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
doWork,
|
|
32
|
+
doWorkAndYield
|
|
33
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@altano/tiny-async-pool",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Run multiple promise-returning & async functions with limited concurrency using native ES9",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"LICENSE-MIT",
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup src/index.ts --format esm --dts",
|
|
15
|
+
"dev": "tsup src/index.ts --watch --format esm --dts",
|
|
16
|
+
"format": "prettier --write src",
|
|
17
|
+
"lint": "TIMING=1 eslint src/**/*.ts* --fix",
|
|
18
|
+
"clean": "rm -rf .turbo && rm -rf .tsbuildinfo && rm -rf node_modules && rm -rf dist",
|
|
19
|
+
"test": "vitest --run",
|
|
20
|
+
"test:watch": "vitest"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git@github.com:altano/async-pool.git"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"race",
|
|
28
|
+
"concurrency",
|
|
29
|
+
"promise",
|
|
30
|
+
"async",
|
|
31
|
+
"async iterator",
|
|
32
|
+
"async iteration",
|
|
33
|
+
"async generator",
|
|
34
|
+
"es9"
|
|
35
|
+
],
|
|
36
|
+
"author": {
|
|
37
|
+
"name": "Alan Norbauer",
|
|
38
|
+
"email": "altano@gmail.com",
|
|
39
|
+
"url": "https://alan.norbauer.com"
|
|
40
|
+
},
|
|
41
|
+
"contributors": [
|
|
42
|
+
"Rafael Xavier de Souza"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@altano/tsconfig": "*",
|
|
47
|
+
"@types/node": "^18.6.4",
|
|
48
|
+
"@types/prettier": "^2.7.0",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^5.36.1",
|
|
50
|
+
"@typescript-eslint/parser": "^5.36.1",
|
|
51
|
+
"@vitest/ui": "^0.21.0",
|
|
52
|
+
"chai-as-promised": "^7.1.1",
|
|
53
|
+
"chai": "^4.3.6",
|
|
54
|
+
"eslint-config-altano": "*",
|
|
55
|
+
"eslint-config-prettier": "^8.5.0",
|
|
56
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
57
|
+
"eslint": "^8.23.0",
|
|
58
|
+
"mocha": "^10.0.0",
|
|
59
|
+
"prettier": "^2.7.1",
|
|
60
|
+
"tsup": "^6.2.3",
|
|
61
|
+
"typescript": "^4.8.2",
|
|
62
|
+
"vitest": "^0.21.0"
|
|
63
|
+
},
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"access": "public"
|
|
66
|
+
}
|
|
67
|
+
}
|