@shutterstock/p-map-iterable 1.1.0 → 1.1.2
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/README.md +105 -14
- package/dist/src/iterable-mapper.d.ts +173 -30
- package/dist/src/iterable-mapper.js +143 -25
- package/dist/src/iterable-mapper.js.map +1 -1
- package/dist/src/iterable-queue-mapper-simple.d.ts +44 -29
- package/dist/src/iterable-queue-mapper-simple.js +38 -21
- package/dist/src/iterable-queue-mapper-simple.js.map +1 -1
- package/dist/src/iterable-queue-mapper.d.ts +38 -58
- package/dist/src/iterable-queue-mapper.js +33 -33
- package/dist/src/iterable-queue-mapper.js.map +1 -1
- package/package.json +3 -3
- package/dist/src/blocking-queue.d.ts.map +0 -1
- package/dist/src/blocking-queue.test.d.ts +0 -2
- package/dist/src/blocking-queue.test.d.ts.map +0 -1
- package/dist/src/blocking-queue.test.js +0 -174
- package/dist/src/blocking-queue.test.js.map +0 -1
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/iterable-mapper.d.ts.map +0 -1
- package/dist/src/iterable-mapper.test.d.ts +0 -2
- package/dist/src/iterable-mapper.test.d.ts.map +0 -1
- package/dist/src/iterable-mapper.test.js +0 -870
- package/dist/src/iterable-mapper.test.js.map +0 -1
- package/dist/src/iterable-queue-mapper-simple.d.ts.map +0 -1
- package/dist/src/iterable-queue-mapper-simple.test.d.ts +0 -2
- package/dist/src/iterable-queue-mapper-simple.test.d.ts.map +0 -1
- package/dist/src/iterable-queue-mapper-simple.test.js +0 -102
- package/dist/src/iterable-queue-mapper-simple.test.js.map +0 -1
- package/dist/src/iterable-queue-mapper.d.ts.map +0 -1
- package/dist/src/iterable-queue-mapper.test.d.ts +0 -2
- package/dist/src/iterable-queue-mapper.test.d.ts.map +0 -1
- package/dist/src/iterable-queue-mapper.test.js +0 -117
- package/dist/src/iterable-queue-mapper.test.js.map +0 -1
- package/dist/src/iterable-queue.d.ts.map +0 -1
- package/dist/src/iterable-queue.test.d.ts +0 -2
- package/dist/src/iterable-queue.test.d.ts.map +0 -1
- package/dist/src/iterable-queue.test.js +0 -143
- package/dist/src/iterable-queue.test.js.map +0 -1
- package/dist/src/queue.d.ts.map +0 -1
- package/dist/src/queue.test.d.ts +0 -2
- package/dist/src/queue.test.d.ts.map +0 -1
- package/dist/src/queue.test.js +0 -75
- package/dist/src/queue.test.js.map +0 -1
|
@@ -1,29 +1,53 @@
|
|
|
1
|
-
import { Mapper } from './iterable-mapper';
|
|
1
|
+
import { IterableMapperOptions, Mapper } from './iterable-mapper';
|
|
2
2
|
type Errors<T> = {
|
|
3
3
|
item: T;
|
|
4
4
|
error: string | {
|
|
5
5
|
[key: string]: any;
|
|
6
6
|
} | Error;
|
|
7
7
|
}[];
|
|
8
|
+
/**
|
|
9
|
+
* Options for IterableQueueMapperSimple
|
|
10
|
+
*/
|
|
11
|
+
export type IterableQueueMapperSimpleOptions = Pick<IterableMapperOptions, 'concurrency'>;
|
|
8
12
|
/**
|
|
9
13
|
* Accepts queue items via `enqueue` and calls the `mapper` on them
|
|
10
|
-
* with specified concurrency,
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
+
* with specified `concurrency`, discards the results, and accumulates
|
|
15
|
+
* exceptions in the `errors` property. When empty, `await enqueue()`
|
|
16
|
+
* will return immediately, but when `concurrency` items are in progress,
|
|
17
|
+
* `await enqueue()` will block until a slot is available to accept the item.
|
|
14
18
|
*
|
|
15
19
|
* @remarks
|
|
16
20
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
21
|
+
* ### Typical Use Case
|
|
22
|
+
* - Pushing items to an async I/O destination
|
|
23
|
+
* - In the simple sequential (`concurrency: 1`) case, allows 1 item to be flushed async while caller prepares next item
|
|
24
|
+
* - Results of the flushed items are not needed in a subsequent step (if they are, use `IterableQueueMapper`)
|
|
25
|
+
*
|
|
26
|
+
* ### Error Handling
|
|
27
|
+
* The mapper should ideally handle all errors internally to enable error handling
|
|
28
|
+
* closest to where they occur. However, if errors do escape the mapper:
|
|
29
|
+
* - Processing continues despite errors
|
|
30
|
+
* - All errors are collected in the `errors` property
|
|
31
|
+
* - Errors can be checked/handled during processing via the `errors` property
|
|
32
|
+
*
|
|
33
|
+
* Key Differences from `IterableQueueMapper`:
|
|
34
|
+
* - `maxUnread` defaults to equal `concurrency` (simplifying queue management)
|
|
35
|
+
* - Results are automatically iterated and discarded (all work should happen in mapper)
|
|
36
|
+
* - Errors are collected rather than thrown (available via errors property)
|
|
19
37
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
38
|
+
* ### Usage
|
|
39
|
+
* - Items are added to the queue via the `await enqueue()` method
|
|
40
|
+
* - Check `errors` property to see if any errors occurred, stop if desired
|
|
41
|
+
* - IMPORTANT: `await enqueue()` method will block until a slot is available, if queue is full
|
|
42
|
+
* - IMPORTANT: Always `await onIdle()` to ensure all items are processed
|
|
22
43
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
44
|
+
* Note: the name is somewhat of a misnomer as this wraps `IterableQueueMapper`
|
|
45
|
+
* but is not itself an `Iterable`.
|
|
25
46
|
*
|
|
26
47
|
* @category Enqueue Input
|
|
48
|
+
*
|
|
49
|
+
* @see {@link IterableQueueMapper} for related class with more configuration options
|
|
50
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
27
51
|
*/
|
|
28
52
|
export declare class IterableQueueMapperSimple<Element> {
|
|
29
53
|
private readonly _writer;
|
|
@@ -32,26 +56,17 @@ export declare class IterableQueueMapperSimple<Element> {
|
|
|
32
56
|
private readonly _mapper;
|
|
33
57
|
private _isIdle;
|
|
34
58
|
/**
|
|
35
|
-
* Create a new `IterableQueueMapperSimple`
|
|
59
|
+
* Create a new `IterableQueueMapperSimple`, which uses `IterableQueueMapper` underneath, but
|
|
60
|
+
* automatically iterates and discards results as they complete.
|
|
36
61
|
*
|
|
37
|
-
* @param mapper Function
|
|
38
|
-
* Expected to return a `Promise` or value.
|
|
39
|
-
*
|
|
40
|
-
* The `mapper` *should* handle all errors and not allow an error to be thrown
|
|
41
|
-
* out of the `mapper` function as this enables the best handling of errors
|
|
42
|
-
* closest to the time that they occur.
|
|
43
|
-
*
|
|
44
|
-
* If the `mapper` function does allow an error to be thrown then the
|
|
45
|
-
* errors will be accumulated in the `errors` property.
|
|
62
|
+
* @param mapper Function called for every enqueued item. Returns a `Promise` or value.
|
|
46
63
|
* @param options IterableQueueMapperSimple options
|
|
64
|
+
*
|
|
65
|
+
* @see {@link IterableQueueMapperSimple} for full class documentation
|
|
66
|
+
* @see {@link IterableQueueMapper} for related class with more configuration options
|
|
67
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
47
68
|
*/
|
|
48
|
-
constructor(mapper: Mapper<Element, void>, options?:
|
|
49
|
-
/**
|
|
50
|
-
* Number of items to accept for mapping before requiring the caller to wait for one to complete.
|
|
51
|
-
* @default 4
|
|
52
|
-
*/
|
|
53
|
-
concurrency?: number;
|
|
54
|
-
});
|
|
69
|
+
constructor(mapper: Mapper<Element, void>, options?: IterableQueueMapperSimpleOptions);
|
|
55
70
|
private discardResults;
|
|
56
71
|
private worker;
|
|
57
72
|
/**
|
|
@@ -70,7 +85,7 @@ export declare class IterableQueueMapperSimple<Element> {
|
|
|
70
85
|
/**
|
|
71
86
|
* Accept a request for sending in the background if a concurrency slot is available.
|
|
72
87
|
* Else, do not return until a concurrency slot is freed up.
|
|
73
|
-
* This provides concurrency background writes with
|
|
88
|
+
* This provides concurrency background writes with backpressure to prevent
|
|
74
89
|
* the caller from getting too far ahead.
|
|
75
90
|
*
|
|
76
91
|
* MUST await `onIdle` for background `mappers`s to finish
|
|
@@ -5,38 +5,55 @@ const iterable_queue_mapper_1 = require("./iterable-queue-mapper");
|
|
|
5
5
|
const NoResult = Symbol('noresult');
|
|
6
6
|
/**
|
|
7
7
|
* Accepts queue items via `enqueue` and calls the `mapper` on them
|
|
8
|
-
* with specified concurrency,
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* with specified `concurrency`, discards the results, and accumulates
|
|
9
|
+
* exceptions in the `errors` property. When empty, `await enqueue()`
|
|
10
|
+
* will return immediately, but when `concurrency` items are in progress,
|
|
11
|
+
* `await enqueue()` will block until a slot is available to accept the item.
|
|
12
12
|
*
|
|
13
13
|
* @remarks
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* ### Typical Use Case
|
|
16
|
+
* - Pushing items to an async I/O destination
|
|
17
|
+
* - In the simple sequential (`concurrency: 1`) case, allows 1 item to be flushed async while caller prepares next item
|
|
18
|
+
* - Results of the flushed items are not needed in a subsequent step (if they are, use `IterableQueueMapper`)
|
|
19
|
+
*
|
|
20
|
+
* ### Error Handling
|
|
21
|
+
* The mapper should ideally handle all errors internally to enable error handling
|
|
22
|
+
* closest to where they occur. However, if errors do escape the mapper:
|
|
23
|
+
* - Processing continues despite errors
|
|
24
|
+
* - All errors are collected in the `errors` property
|
|
25
|
+
* - Errors can be checked/handled during processing via the `errors` property
|
|
17
26
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
27
|
+
* Key Differences from `IterableQueueMapper`:
|
|
28
|
+
* - `maxUnread` defaults to equal `concurrency` (simplifying queue management)
|
|
29
|
+
* - Results are automatically iterated and discarded (all work should happen in mapper)
|
|
30
|
+
* - Errors are collected rather than thrown (available via errors property)
|
|
20
31
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
32
|
+
* ### Usage
|
|
33
|
+
* - Items are added to the queue via the `await enqueue()` method
|
|
34
|
+
* - Check `errors` property to see if any errors occurred, stop if desired
|
|
35
|
+
* - IMPORTANT: `await enqueue()` method will block until a slot is available, if queue is full
|
|
36
|
+
* - IMPORTANT: Always `await onIdle()` to ensure all items are processed
|
|
37
|
+
*
|
|
38
|
+
* Note: the name is somewhat of a misnomer as this wraps `IterableQueueMapper`
|
|
39
|
+
* but is not itself an `Iterable`.
|
|
23
40
|
*
|
|
24
41
|
* @category Enqueue Input
|
|
42
|
+
*
|
|
43
|
+
* @see {@link IterableQueueMapper} for related class with more configuration options
|
|
44
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
25
45
|
*/
|
|
26
46
|
class IterableQueueMapperSimple {
|
|
27
47
|
/**
|
|
28
|
-
* Create a new `IterableQueueMapperSimple`
|
|
29
|
-
*
|
|
30
|
-
* @param mapper Function which is called for every item in `input`.
|
|
31
|
-
* Expected to return a `Promise` or value.
|
|
48
|
+
* Create a new `IterableQueueMapperSimple`, which uses `IterableQueueMapper` underneath, but
|
|
49
|
+
* automatically iterates and discards results as they complete.
|
|
32
50
|
*
|
|
33
|
-
*
|
|
34
|
-
* out of the `mapper` function as this enables the best handling of errors
|
|
35
|
-
* closest to the time that they occur.
|
|
36
|
-
*
|
|
37
|
-
* If the `mapper` function does allow an error to be thrown then the
|
|
38
|
-
* errors will be accumulated in the `errors` property.
|
|
51
|
+
* @param mapper Function called for every enqueued item. Returns a `Promise` or value.
|
|
39
52
|
* @param options IterableQueueMapperSimple options
|
|
53
|
+
*
|
|
54
|
+
* @see {@link IterableQueueMapperSimple} for full class documentation
|
|
55
|
+
* @see {@link IterableQueueMapper} for related class with more configuration options
|
|
56
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
40
57
|
*/
|
|
41
58
|
constructor(mapper, options = {}) {
|
|
42
59
|
this._errors = [];
|
|
@@ -85,7 +102,7 @@ class IterableQueueMapperSimple {
|
|
|
85
102
|
/**
|
|
86
103
|
* Accept a request for sending in the background if a concurrency slot is available.
|
|
87
104
|
* Else, do not return until a concurrency slot is freed up.
|
|
88
|
-
* This provides concurrency background writes with
|
|
105
|
+
* This provides concurrency background writes with backpressure to prevent
|
|
89
106
|
* the caller from getting too far ahead.
|
|
90
107
|
*
|
|
91
108
|
* MUST await `onIdle` for background `mappers`s to finish
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iterable-queue-mapper-simple.js","sourceRoot":"","sources":["../../src/iterable-queue-mapper-simple.ts"],"names":[],"mappings":";;;AACA,mEAA8D;AAK9D,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"iterable-queue-mapper-simple.js","sourceRoot":"","sources":["../../src/iterable-queue-mapper-simple.ts"],"names":[],"mappings":";;;AACA,mEAA8D;AAK9D,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAOpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAa,yBAAyB;IAOpC;;;;;;;;;;OAUG;IACH,YAAY,MAA6B,EAAE,UAA4C,EAAE;QAhBxE,YAAO,GAAoB,EAAE,CAAC;QAGvC,YAAO,GAAG,KAAK,CAAC;QActB,MAAM,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;QAEpC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,IAAI,2CAAmB,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;QAE7F,6BAA6B;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,cAAc;QAC1B,6DAA6D;QAC7D,IAAI,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE;YACzB,+BAA+B;YAC/B,oEAAoE;YACpE,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;SAClC;IACH,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,IAAa,EAAE,KAAa;QAC/C,IAAI;YACF,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAChC,8DAA8D;SAC/D;QAAC,OAAO,KAAU,EAAE;YACnB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;SACpC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,OAAO,CAAC,IAAa;QAChC,4EAA4E;QAC5E,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;;OAGG;IACI,KAAK,CAAC,MAAM;QACjB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,4CAA4C;QAC5C,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QAEpB,MAAM,IAAI,CAAC,KAAK,CAAC;QAEjB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CACF;AAtGD,8DAsGC"}
|
|
@@ -1,77 +1,57 @@
|
|
|
1
|
-
import { Mapper } from './iterable-mapper';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Must be an integer from 1 and up or `Infinity`, must be <= `maxUnread`.
|
|
7
|
-
*
|
|
8
|
-
* @default 4
|
|
9
|
-
*/
|
|
10
|
-
readonly concurrency?: number;
|
|
11
|
-
/**
|
|
12
|
-
* Number of pending unread iterable items.
|
|
13
|
-
*
|
|
14
|
-
* Must be an integer from 1 and up or `Infinity`, must be >= `concurrency`.
|
|
15
|
-
*
|
|
16
|
-
* @default 8
|
|
17
|
-
*/
|
|
18
|
-
readonly maxUnread?: number;
|
|
19
|
-
/**
|
|
20
|
-
* When set to `false`, instead of stopping when a promise rejects, it will wait for all the promises to settle and then reject with an [aggregated error](https://github.com/sindresorhus/aggregate-error) containing all the errors from the rejected promises.
|
|
21
|
-
*
|
|
22
|
-
* @default true
|
|
23
|
-
*/
|
|
24
|
-
readonly stopOnMapperError?: boolean;
|
|
25
|
-
}
|
|
1
|
+
import { IterableMapperOptions, Mapper } from './iterable-mapper';
|
|
2
|
+
/**
|
|
3
|
+
* Options for IterableQueueMapper
|
|
4
|
+
*/
|
|
5
|
+
export type IterableQueueMapperOptions = IterableMapperOptions;
|
|
26
6
|
/**
|
|
27
7
|
* Accepts queue items via `enqueue` and calls the `mapper` on them
|
|
28
|
-
* with specified concurrency
|
|
29
|
-
* `
|
|
30
|
-
*
|
|
31
|
-
* the queue is full, until an item is read.
|
|
8
|
+
* with specified `concurrency`, storing the `mapper` result in a queue
|
|
9
|
+
* of `maxUnread` size, before being iterated / read by the caller.
|
|
10
|
+
* The `enqueue` method will block if the queue is full, until an item is read.
|
|
32
11
|
*
|
|
33
12
|
* @remarks
|
|
34
13
|
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
14
|
+
* ### Typical Use Case
|
|
15
|
+
* - Pushing items to an async I/O destination
|
|
16
|
+
* - In the simple sequential (`concurrency: 1`) case, allows 1 item to be flushed async while caller prepares next item
|
|
17
|
+
* - Results of the flushed items are needed in a subsequent step (if they are not, use `IterableQueueMapperSimple`)
|
|
18
|
+
* - Prevents the producer from racing ahead of the consumer if `maxUnread` is reached
|
|
19
|
+
*
|
|
20
|
+
* ### Error Handling
|
|
21
|
+
* The mapper should ideally handle all errors internally to enable error handling
|
|
22
|
+
* closest to where they occur. However, if errors do escape the mapper:
|
|
38
23
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* `mapper` function of the `IterableMapper`.
|
|
24
|
+
* When `stopOnMapperError` is true (default):
|
|
25
|
+
* - First error immediately stops processing
|
|
26
|
+
* - Error is thrown from the `AsyncIterator`'s next() call
|
|
43
27
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
28
|
+
* When `stopOnMapperError` is false:
|
|
29
|
+
* - Processing continues despite errors
|
|
30
|
+
* - All errors are collected and thrown together
|
|
31
|
+
* - Errors are thrown as `AggregateError` after all items complete
|
|
32
|
+
*
|
|
33
|
+
* ### Usage
|
|
34
|
+
* - Items are added to the queue via the `await enqueue()` method
|
|
35
|
+
* - IMPORTANT: `await enqueue()` method will block until a slot is available, if queue is full
|
|
36
|
+
* - Call `done()` when no more items will be enqueued
|
|
37
|
+
* - IMPORTANT: Always `await onIdle()` to ensure all items are processed
|
|
50
38
|
*
|
|
51
39
|
* @category Enqueue Input
|
|
40
|
+
*
|
|
41
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
52
42
|
*/
|
|
53
43
|
export declare class IterableQueueMapper<Element, NewElement> implements AsyncIterable<NewElement> {
|
|
54
44
|
private _iterableMapper;
|
|
55
45
|
private _sourceIterable;
|
|
56
46
|
/**
|
|
57
|
-
* Create a new `IterableQueueMapper`
|
|
58
|
-
*
|
|
59
|
-
* @param mapper Function which is called for every item in `input`.
|
|
60
|
-
* Expected to return a `Promise` or value.
|
|
47
|
+
* Create a new `IterableQueueMapper`, which uses `IterableMapper` underneath, and exposes a
|
|
48
|
+
* queue interface for adding items that are not exposed via an iterator.
|
|
61
49
|
*
|
|
62
|
-
*
|
|
63
|
-
* out of the `mapper` function as this enables the best handling of errors
|
|
64
|
-
* closest to the time that they occur.
|
|
65
|
-
*
|
|
66
|
-
* If the `mapper` function does allow an error to be thrown then the
|
|
67
|
-
* `stopOnMapperError` option controls the behavior:
|
|
68
|
-
* - `stopOnMapperError`: `true` - will throw the error
|
|
69
|
-
* out of `next` or the `AsyncIterator` returned from `[Symbol.asyncIterator]`
|
|
70
|
-
* and stop processing.
|
|
71
|
-
* - `stopOnMapperError`: `false` - will continue processing
|
|
72
|
-
* and accumulate the errors to be thrown from `next` or the `AsyncIterator`
|
|
73
|
-
* returned from `[Symbol.asyncIterator]` when all items have been processed.
|
|
50
|
+
* @param mapper Function called for every enqueued item. Returns a `Promise` or value.
|
|
74
51
|
* @param options IterableQueueMapper options
|
|
52
|
+
*
|
|
53
|
+
* @see {@link IterableQueueMapper} for full class documentation
|
|
54
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
75
55
|
*/
|
|
76
56
|
constructor(mapper: Mapper<Element, NewElement>, options?: IterableQueueMapperOptions);
|
|
77
57
|
[Symbol.asyncIterator](): AsyncIterator<NewElement>;
|
|
@@ -8,51 +8,51 @@ const iterable_mapper_1 = require("./iterable-mapper");
|
|
|
8
8
|
const iterable_queue_1 = require("./iterable-queue");
|
|
9
9
|
/**
|
|
10
10
|
* Accepts queue items via `enqueue` and calls the `mapper` on them
|
|
11
|
-
* with specified concurrency
|
|
12
|
-
* `
|
|
13
|
-
*
|
|
14
|
-
* the queue is full, until an item is read.
|
|
11
|
+
* with specified `concurrency`, storing the `mapper` result in a queue
|
|
12
|
+
* of `maxUnread` size, before being iterated / read by the caller.
|
|
13
|
+
* The `enqueue` method will block if the queue is full, until an item is read.
|
|
15
14
|
*
|
|
16
15
|
* @remarks
|
|
17
16
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* ### Typical Use Case
|
|
18
|
+
* - Pushing items to an async I/O destination
|
|
19
|
+
* - In the simple sequential (`concurrency: 1`) case, allows 1 item to be flushed async while caller prepares next item
|
|
20
|
+
* - Results of the flushed items are needed in a subsequent step (if they are not, use `IterableQueueMapperSimple`)
|
|
21
|
+
* - Prevents the producer from racing ahead of the consumer if `maxUnread` is reached
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* `mapper` function of the `IterableMapper`.
|
|
23
|
+
* ### Error Handling
|
|
24
|
+
* The mapper should ideally handle all errors internally to enable error handling
|
|
25
|
+
* closest to where they occur. However, if errors do escape the mapper:
|
|
26
26
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* `
|
|
32
|
-
*
|
|
27
|
+
* When `stopOnMapperError` is true (default):
|
|
28
|
+
* - First error immediately stops processing
|
|
29
|
+
* - Error is thrown from the `AsyncIterator`'s next() call
|
|
30
|
+
*
|
|
31
|
+
* When `stopOnMapperError` is false:
|
|
32
|
+
* - Processing continues despite errors
|
|
33
|
+
* - All errors are collected and thrown together
|
|
34
|
+
* - Errors are thrown as `AggregateError` after all items complete
|
|
35
|
+
*
|
|
36
|
+
* ### Usage
|
|
37
|
+
* - Items are added to the queue via the `await enqueue()` method
|
|
38
|
+
* - IMPORTANT: `await enqueue()` method will block until a slot is available, if queue is full
|
|
39
|
+
* - Call `done()` when no more items will be enqueued
|
|
40
|
+
* - IMPORTANT: Always `await onIdle()` to ensure all items are processed
|
|
33
41
|
*
|
|
34
42
|
* @category Enqueue Input
|
|
43
|
+
*
|
|
44
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
35
45
|
*/
|
|
36
46
|
class IterableQueueMapper {
|
|
37
47
|
/**
|
|
38
|
-
* Create a new `IterableQueueMapper`
|
|
48
|
+
* Create a new `IterableQueueMapper`, which uses `IterableMapper` underneath, and exposes a
|
|
49
|
+
* queue interface for adding items that are not exposed via an iterator.
|
|
39
50
|
*
|
|
40
|
-
* @param mapper Function
|
|
41
|
-
* Expected to return a `Promise` or value.
|
|
42
|
-
*
|
|
43
|
-
* The `mapper` *should* handle all errors and not allow an error to be thrown
|
|
44
|
-
* out of the `mapper` function as this enables the best handling of errors
|
|
45
|
-
* closest to the time that they occur.
|
|
46
|
-
*
|
|
47
|
-
* If the `mapper` function does allow an error to be thrown then the
|
|
48
|
-
* `stopOnMapperError` option controls the behavior:
|
|
49
|
-
* - `stopOnMapperError`: `true` - will throw the error
|
|
50
|
-
* out of `next` or the `AsyncIterator` returned from `[Symbol.asyncIterator]`
|
|
51
|
-
* and stop processing.
|
|
52
|
-
* - `stopOnMapperError`: `false` - will continue processing
|
|
53
|
-
* and accumulate the errors to be thrown from `next` or the `AsyncIterator`
|
|
54
|
-
* returned from `[Symbol.asyncIterator]` when all items have been processed.
|
|
51
|
+
* @param mapper Function called for every enqueued item. Returns a `Promise` or value.
|
|
55
52
|
* @param options IterableQueueMapper options
|
|
53
|
+
*
|
|
54
|
+
* @see {@link IterableQueueMapper} for full class documentation
|
|
55
|
+
* @see {@link IterableMapper} for underlying mapper implementation and examples of combined usage
|
|
56
56
|
*/
|
|
57
57
|
constructor(mapper, options = {}) {
|
|
58
58
|
this._sourceIterable = new iterable_queue_1.IterableQueue({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"iterable-queue-mapper.js","sourceRoot":"","sources":["../../src/iterable-queue-mapper.ts"],"names":[],"mappings":";;;AAAA,EAAE;AACF,sGAAsG;AACtG,EAAE;AACF,
|
|
1
|
+
{"version":3,"file":"iterable-queue-mapper.js","sourceRoot":"","sources":["../../src/iterable-queue-mapper.ts"],"names":[],"mappings":";;;AAAA,EAAE;AACF,sGAAsG;AACtG,EAAE;AACF,uDAAkF;AAClF,qDAAiD;AAOjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,MAAa,mBAAmB;IAK9B;;;;;;;;;OASG;IACH,YAAY,MAAmC,EAAE,UAAsC,EAAE;QACvF,IAAI,CAAC,eAAe,GAAG,IAAI,8BAAa,CAAC;YACvC,SAAS,EAAE,CAAC;SACb,CAAC,CAAC;QACH,IAAI,CAAC,eAAe,GAAG,IAAI,gCAAc,CAAC,IAAI,CAAC,eAAe,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IACnF,CAAC;IAEM,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,IAAI;QACf,OAAO,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IACrC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,OAAO,CAAC,IAAa;QAChC,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED;;;;OAIG;IACI,IAAI;QACT,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;CACF;AApDD,kDAoDC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shutterstock/p-map-iterable",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "Set of classes
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "Set of classes used for async prefetching with backpressure (IterableMapper) and async flushing with backpressure (IterableQueueMapper, IterableQueueMapperSimple)",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
7
7
|
"publishConfig": {
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"AsyncIterator"
|
|
25
25
|
],
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "tsc --build tsconfig.json && echo 'examples/\n*.tsbuildinfo' > dist/.npmignore",
|
|
27
|
+
"build": "tsc --build tsconfig.json && echo 'examples/\n*.tsbuildinfo\n*.test.*\n*.d.ts.map' > dist/.npmignore",
|
|
28
28
|
"build:docs": "typedoc src/index.ts",
|
|
29
29
|
"example:iterable-mapper": "ts-node -r tsconfig-paths/register examples/iterable-mapper.ts",
|
|
30
30
|
"example:iterable-queue-mapper": "ts-node -r tsconfig-paths/register examples/iterable-queue-mapper.ts",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blocking-queue.d.ts","sourceRoot":"","sources":["../../src/blocking-queue.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,oBAAoB;IACnC;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAOD;;;;;;;GAOG;AACH,qBAAa,aAAa,CAAC,OAAO;IAChC,OAAO,CAAC,QAAQ,CAAiC;IAKjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA+B;IAO5D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0C;IAO1E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA0C;IAE1E,OAAO,CAAC,WAAW,CAAS;IAE5B;;;;OAIG;gBACS,OAAO,GAAE,oBAAyB;IAuB9C,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED;;;;OAIG;IACI,IAAI,IAAI,IAAI;IAcnB;;;;OAIG;IACU,OAAO,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IA0BlD;;;;OAIG;IACU,OAAO,IAAI,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAoCpD,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,SAAS;IAqCjB;;OAEG;YACW,YAAY;IAW1B;;OAEG;YACW,WAAW;CAU1B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blocking-queue.test.d.ts","sourceRoot":"","sources":["../../src/blocking-queue.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
/// <reference types="jest" />
|
|
4
|
-
const blocking_queue_1 = require("./blocking-queue");
|
|
5
|
-
describe('BlockingQueue', () => {
|
|
6
|
-
beforeAll(() => {
|
|
7
|
-
// nothing
|
|
8
|
-
});
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
jest.clearAllMocks();
|
|
11
|
-
});
|
|
12
|
-
describe('maxUnread: 0', () => {
|
|
13
|
-
it('single item enqueue/dequeue works', async () => {
|
|
14
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 0 });
|
|
15
|
-
setTimeout(() => {
|
|
16
|
-
void queue.enqueue(1);
|
|
17
|
-
}, 1000);
|
|
18
|
-
const item = await queue.dequeue();
|
|
19
|
-
queue.done();
|
|
20
|
-
expect(item).toBe(1);
|
|
21
|
-
});
|
|
22
|
-
it('dequeue after done does not hang', async () => {
|
|
23
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 0 });
|
|
24
|
-
setTimeout(() => {
|
|
25
|
-
void queue.enqueue(1);
|
|
26
|
-
}, 1000);
|
|
27
|
-
const item = await queue.dequeue();
|
|
28
|
-
queue.done();
|
|
29
|
-
await queue.dequeue();
|
|
30
|
-
expect(item).toBe(1);
|
|
31
|
-
});
|
|
32
|
-
it('enqueue after done throws', async () => {
|
|
33
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 0 });
|
|
34
|
-
setTimeout(() => {
|
|
35
|
-
void queue.enqueue(1);
|
|
36
|
-
}, 1000);
|
|
37
|
-
const item = await queue.dequeue();
|
|
38
|
-
queue.done();
|
|
39
|
-
await expect(async () => queue.enqueue(2)).rejects.toThrowError('`enqueue` called after `done` called');
|
|
40
|
-
expect(item).toBe(1);
|
|
41
|
-
});
|
|
42
|
-
it('balanced enqueue/dequeue works', async () => {
|
|
43
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 0 });
|
|
44
|
-
const writers = [];
|
|
45
|
-
writers.push(queue.enqueue(1));
|
|
46
|
-
writers.push(queue.enqueue(2));
|
|
47
|
-
const readers = [];
|
|
48
|
-
readers.push(queue.dequeue());
|
|
49
|
-
readers.push(queue.dequeue());
|
|
50
|
-
await Promise.all(writers);
|
|
51
|
-
queue.done();
|
|
52
|
-
await Promise.all(readers);
|
|
53
|
-
expect(await readers[0]).toBe(1);
|
|
54
|
-
expect(await readers[1]).toBe(2);
|
|
55
|
-
});
|
|
56
|
-
it('full queue blocks enqueue until dequeue', async () => {
|
|
57
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
58
|
-
// Add first item
|
|
59
|
-
void queue.enqueue(1);
|
|
60
|
-
// Do not wait for second item to add (it will wait until an enqueue completes)
|
|
61
|
-
setTimeout(() => {
|
|
62
|
-
void queue.enqueue(2);
|
|
63
|
-
}, 2000);
|
|
64
|
-
const startTime = Date.now();
|
|
65
|
-
expect(await queue.dequeue()).toBe(1);
|
|
66
|
-
expect(Date.now() - startTime).toBeLessThan(2000);
|
|
67
|
-
expect(await queue.dequeue()).toBe(2);
|
|
68
|
-
expect(Date.now() - startTime).toBeGreaterThanOrEqual(2000);
|
|
69
|
-
queue.done();
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
describe('maxUnread: 1', () => {
|
|
73
|
-
it('single item enqueue/dequeue works', async () => {
|
|
74
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
75
|
-
await queue.enqueue(1);
|
|
76
|
-
const item = await queue.dequeue();
|
|
77
|
-
queue.done();
|
|
78
|
-
expect(item).toBe(1);
|
|
79
|
-
});
|
|
80
|
-
it('dequeue after done does not hang', async () => {
|
|
81
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
82
|
-
await queue.enqueue(1);
|
|
83
|
-
const item = await queue.dequeue();
|
|
84
|
-
queue.done();
|
|
85
|
-
await queue.dequeue();
|
|
86
|
-
expect(item).toBe(1);
|
|
87
|
-
});
|
|
88
|
-
it('dequeue after done and empty does not hang', async () => {
|
|
89
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
90
|
-
await queue.enqueue(1);
|
|
91
|
-
const item = await queue.dequeue();
|
|
92
|
-
queue.done();
|
|
93
|
-
await queue.dequeue();
|
|
94
|
-
expect(item).toBe(1);
|
|
95
|
-
await queue.dequeue();
|
|
96
|
-
});
|
|
97
|
-
it('enqueue after done throws', async () => {
|
|
98
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
99
|
-
await queue.enqueue(1);
|
|
100
|
-
const item = await queue.dequeue();
|
|
101
|
-
queue.done();
|
|
102
|
-
await expect(async () => queue.enqueue(2)).rejects.toThrowError('`enqueue` called after `done` called');
|
|
103
|
-
expect(item).toBe(1);
|
|
104
|
-
});
|
|
105
|
-
it('balanced enqueue/dequeue works', async () => {
|
|
106
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
107
|
-
const writers = [];
|
|
108
|
-
writers.push(queue.enqueue(1));
|
|
109
|
-
writers.push(queue.enqueue(2));
|
|
110
|
-
const readers = [];
|
|
111
|
-
readers.push(queue.dequeue());
|
|
112
|
-
readers.push(queue.dequeue());
|
|
113
|
-
await Promise.all(writers);
|
|
114
|
-
queue.done();
|
|
115
|
-
await Promise.all(readers);
|
|
116
|
-
expect(await readers[0]).toBe(1);
|
|
117
|
-
expect(await readers[1]).toBe(2);
|
|
118
|
-
});
|
|
119
|
-
it('more dequeue than enqueue works', async () => {
|
|
120
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
121
|
-
const writers = [];
|
|
122
|
-
writers.push(queue.enqueue(1));
|
|
123
|
-
writers.push(queue.enqueue(2));
|
|
124
|
-
const readers = [];
|
|
125
|
-
readers.push(queue.dequeue());
|
|
126
|
-
readers.push(queue.dequeue());
|
|
127
|
-
readers.push(queue.dequeue());
|
|
128
|
-
readers.push(queue.dequeue());
|
|
129
|
-
await Promise.all(writers);
|
|
130
|
-
queue.done();
|
|
131
|
-
await Promise.all(readers);
|
|
132
|
-
expect(await readers[0]).toBe(1);
|
|
133
|
-
expect(await readers[1]).toBe(2);
|
|
134
|
-
expect(await readers[2]).toBeUndefined();
|
|
135
|
-
expect(await readers[3]).toBeUndefined();
|
|
136
|
-
});
|
|
137
|
-
it('full queue blocks enqueue until dequeue', async () => {
|
|
138
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 1 });
|
|
139
|
-
// Wait for first item to add
|
|
140
|
-
await queue.enqueue(1);
|
|
141
|
-
// Do not wait for second item to add (it will wait until an enqueue completes)
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
void queue.enqueue(2);
|
|
144
|
-
}, 2000);
|
|
145
|
-
expect(await queue.dequeue()).toBe(1);
|
|
146
|
-
const startTime = Date.now();
|
|
147
|
-
expect(await queue.dequeue()).toBe(2);
|
|
148
|
-
const duration = Date.now() - startTime;
|
|
149
|
-
expect(duration).toBeGreaterThanOrEqual(2000);
|
|
150
|
-
queue.done();
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe('maxUnread: 2', () => {
|
|
154
|
-
it('no reads until done works', async () => {
|
|
155
|
-
const queue = new blocking_queue_1.BlockingQueue({ maxUnread: 2 });
|
|
156
|
-
const writers = [];
|
|
157
|
-
writers.push(queue.enqueue(1));
|
|
158
|
-
writers.push(queue.enqueue(2));
|
|
159
|
-
await Promise.all(writers);
|
|
160
|
-
queue.done();
|
|
161
|
-
const readers = [];
|
|
162
|
-
readers.push(queue.dequeue());
|
|
163
|
-
readers.push(queue.dequeue());
|
|
164
|
-
readers.push(queue.dequeue());
|
|
165
|
-
readers.push(queue.dequeue());
|
|
166
|
-
await Promise.all(readers);
|
|
167
|
-
expect(await readers[0]).toBe(1);
|
|
168
|
-
expect(await readers[1]).toBe(2);
|
|
169
|
-
expect(await readers[2]).toBeUndefined();
|
|
170
|
-
expect(await readers[3]).toBeUndefined();
|
|
171
|
-
});
|
|
172
|
-
});
|
|
173
|
-
});
|
|
174
|
-
//# sourceMappingURL=blocking-queue.test.js.map
|