@shutterstock/p-map-iterable 1.1.1 → 1.2.0-prerelease.1

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 (49) hide show
  1. package/README.md +79 -17
  2. package/dist/src/blocking-queue.js +6 -20
  3. package/dist/src/blocking-queue.js.map +1 -1
  4. package/dist/src/index.d.ts +3 -2
  5. package/dist/src/index.js +4 -1
  6. package/dist/src/index.js.map +1 -1
  7. package/dist/src/iterable-mapper.d.ts +18 -13
  8. package/dist/src/iterable-mapper.js +28 -45
  9. package/dist/src/iterable-mapper.js.map +1 -1
  10. package/dist/src/iterable-queue-mapper-simple.d.ts +28 -21
  11. package/dist/src/iterable-queue-mapper-simple.js +29 -23
  12. package/dist/src/iterable-queue-mapper-simple.js.map +1 -1
  13. package/dist/src/iterable-queue-mapper.d.ts +18 -9
  14. package/dist/src/iterable-queue-mapper.js +17 -8
  15. package/dist/src/iterable-queue-mapper.js.map +1 -1
  16. package/dist/src/iterable-queue.js.map +1 -1
  17. package/dist/src/queue.js.map +1 -1
  18. package/package.json +25 -19
  19. package/dist/src/blocking-queue.d.ts.map +0 -1
  20. package/dist/src/blocking-queue.test.d.ts +0 -2
  21. package/dist/src/blocking-queue.test.d.ts.map +0 -1
  22. package/dist/src/blocking-queue.test.js +0 -174
  23. package/dist/src/blocking-queue.test.js.map +0 -1
  24. package/dist/src/index.d.ts.map +0 -1
  25. package/dist/src/iterable-mapper.d.ts.map +0 -1
  26. package/dist/src/iterable-mapper.test.d.ts +0 -2
  27. package/dist/src/iterable-mapper.test.d.ts.map +0 -1
  28. package/dist/src/iterable-mapper.test.js +0 -898
  29. package/dist/src/iterable-mapper.test.js.map +0 -1
  30. package/dist/src/iterable-queue-mapper-simple.d.ts.map +0 -1
  31. package/dist/src/iterable-queue-mapper-simple.test.d.ts +0 -2
  32. package/dist/src/iterable-queue-mapper-simple.test.d.ts.map +0 -1
  33. package/dist/src/iterable-queue-mapper-simple.test.js +0 -102
  34. package/dist/src/iterable-queue-mapper-simple.test.js.map +0 -1
  35. package/dist/src/iterable-queue-mapper.d.ts.map +0 -1
  36. package/dist/src/iterable-queue-mapper.test.d.ts +0 -2
  37. package/dist/src/iterable-queue-mapper.test.d.ts.map +0 -1
  38. package/dist/src/iterable-queue-mapper.test.js +0 -119
  39. package/dist/src/iterable-queue-mapper.test.js.map +0 -1
  40. package/dist/src/iterable-queue.d.ts.map +0 -1
  41. package/dist/src/iterable-queue.test.d.ts +0 -2
  42. package/dist/src/iterable-queue.test.d.ts.map +0 -1
  43. package/dist/src/iterable-queue.test.js +0 -143
  44. package/dist/src/iterable-queue.test.js.map +0 -1
  45. package/dist/src/queue.d.ts.map +0 -1
  46. package/dist/src/queue.test.d.ts +0 -2
  47. package/dist/src/queue.test.d.ts.map +0 -1
  48. package/dist/src/queue.test.js +0 -75
  49. package/dist/src/queue.test.js.map +0 -1
@@ -6,22 +6,25 @@ type Errors<T> = {
6
6
  } | Error;
7
7
  }[];
8
8
  /**
9
- * Options for IterableQueueMapperSimple
9
+ * Options for `IterableQueueMapperSimple`, also exported as `WorkerQueueOptions`.
10
10
  */
11
11
  export type IterableQueueMapperSimpleOptions = Pick<IterableMapperOptions, 'concurrency'>;
12
12
  /**
13
13
  * Accepts queue items via `enqueue` and calls the `mapper` on them
14
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.
15
+ * exceptions in the `errors` property. Await `enqueue()` for producer
16
+ * backpressure while the worker callback runs asynchronously.
17
+ *
18
+ * Also exported as `WorkerQueue`, with the same constructor and instance types.
19
+ * Each input uses the same worker callback supplied at construction. Asynchronous
20
+ * work overlaps in the current JavaScript process, and results are consumed internally.
18
21
  *
19
22
  * @remarks
20
23
  *
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`)
24
+ * ### Typical Use Cases
25
+ * - Running background status checks or other queued work through a fixed callback
26
+ * - Sending items to an async I/O destination
27
+ * - Processing items whose return values can be discarded (if results are needed, use `IterableQueueMapper` / `MappingQueue`)
25
28
  *
26
29
  * ### Error Handling
27
30
  * The mapper should ideally handle all errors internally to enable error handling
@@ -31,7 +34,7 @@ export type IterableQueueMapperSimpleOptions = Pick<IterableMapperOptions, 'conc
31
34
  * - Errors can be checked/handled during processing via the `errors` property
32
35
  *
33
36
  * Key Differences from `IterableQueueMapper`:
34
- * - `maxUnread` defaults to equal `concurrency` (simplifying queue management)
37
+ * - The internal `maxUnread` limit equals `concurrency`; only `concurrency` is configurable
35
38
  * - Results are automatically iterated and discarded (all work should happen in mapper)
36
39
  * - Errors are collected rather than thrown (available via errors property)
37
40
  *
@@ -39,7 +42,11 @@ export type IterableQueueMapperSimpleOptions = Pick<IterableMapperOptions, 'conc
39
42
  * - Items are added to the queue via the `await enqueue()` method
40
43
  * - Check `errors` property to see if any errors occurred, stop if desired
41
44
  * - 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
45
+ * - After the last awaited enqueue, await `onIdle()` to close input permanently and finish accepted work
46
+ * - Subsequent enqueues reject, so `onIdle()` is a final shutdown operation
47
+ * - Worker failures are collected in `errors`; they do not reject `onIdle()`
48
+ * - Await each enqueue for producer backpressure; unawaited calls can accumulate pending inputs
49
+ * - Admission limits for event callbacks, cancellation, and per-item completion handles belong to the caller
43
50
  *
44
51
  * Note: the name is somewhat of a misnomer as this wraps `IterableQueueMapper`
45
52
  * but is not itself an `Iterable`.
@@ -70,7 +77,7 @@ export declare class IterableQueueMapperSimple<Element> {
70
77
  private discardResults;
71
78
  private worker;
72
79
  /**
73
- * Accumulated errors from background `mappers`s
80
+ * Accumulated errors from the worker callback.
74
81
  *
75
82
  * @remarks
76
83
  *
@@ -83,24 +90,24 @@ export declare class IterableQueueMapperSimple<Element> {
83
90
  */
84
91
  get errors(): Errors<Element>;
85
92
  /**
86
- * Accept a request for sending in the background if a concurrency slot is available.
87
- * Else, do not return until a concurrency slot is freed up.
88
- * This provides concurrency background writes with backpressure to prevent
89
- * the caller from getting too far ahead.
93
+ * Accept an input for the worker callback, waiting until it can be accepted.
94
+ * Resolves on acceptance, rather than completion of this item's work.
95
+ * Await each enqueue for producer backpressure.
90
96
  *
91
- * MUST await `onIdle` for background `mappers`s to finish
92
- * @param item
97
+ * After the last enqueue, await `onIdle()` to close input and finish accepted work.
98
+ * @param item Input for the worker callback
93
99
  */
94
100
  enqueue(item: Element): Promise<void>;
95
101
  /**
96
- * Wait for all background `mapper`s to finish.
97
- * MUST be called before exit to ensure no lost writes.
102
+ * Permanently close input and wait for all accepted work to finish.
103
+ * Call after the last awaited enqueue. Subsequent enqueues reject.
104
+ * Worker failures are available in `errors` instead of rejecting this wait.
98
105
  */
99
106
  onIdle(): Promise<void>;
100
107
  /**
101
- * Indicates if all background `mapper`s have finished.
108
+ * Indicates whether final shutdown has completed.
102
109
  *
103
- * @returns true if .onIdle() has been called and finished all background writes
110
+ * @returns true after `onIdle()` has finished all accepted work and closed input
104
111
  */
105
112
  get isIdle(): boolean;
106
113
  }
@@ -6,16 +6,19 @@ const NoResult = Symbol('noresult');
6
6
  /**
7
7
  * Accepts queue items via `enqueue` and calls the `mapper` on them
8
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.
9
+ * exceptions in the `errors` property. Await `enqueue()` for producer
10
+ * backpressure while the worker callback runs asynchronously.
11
+ *
12
+ * Also exported as `WorkerQueue`, with the same constructor and instance types.
13
+ * Each input uses the same worker callback supplied at construction. Asynchronous
14
+ * work overlaps in the current JavaScript process, and results are consumed internally.
12
15
  *
13
16
  * @remarks
14
17
  *
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`)
18
+ * ### Typical Use Cases
19
+ * - Running background status checks or other queued work through a fixed callback
20
+ * - Sending items to an async I/O destination
21
+ * - Processing items whose return values can be discarded (if results are needed, use `IterableQueueMapper` / `MappingQueue`)
19
22
  *
20
23
  * ### Error Handling
21
24
  * The mapper should ideally handle all errors internally to enable error handling
@@ -25,7 +28,7 @@ const NoResult = Symbol('noresult');
25
28
  * - Errors can be checked/handled during processing via the `errors` property
26
29
  *
27
30
  * Key Differences from `IterableQueueMapper`:
28
- * - `maxUnread` defaults to equal `concurrency` (simplifying queue management)
31
+ * - The internal `maxUnread` limit equals `concurrency`; only `concurrency` is configurable
29
32
  * - Results are automatically iterated and discarded (all work should happen in mapper)
30
33
  * - Errors are collected rather than thrown (available via errors property)
31
34
  *
@@ -33,7 +36,11 @@ const NoResult = Symbol('noresult');
33
36
  * - Items are added to the queue via the `await enqueue()` method
34
37
  * - Check `errors` property to see if any errors occurred, stop if desired
35
38
  * - 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
39
+ * - After the last awaited enqueue, await `onIdle()` to close input permanently and finish accepted work
40
+ * - Subsequent enqueues reject, so `onIdle()` is a final shutdown operation
41
+ * - Worker failures are collected in `errors`; they do not reject `onIdle()`
42
+ * - Await each enqueue for producer backpressure; unawaited calls can accumulate pending inputs
43
+ * - Admission limits for event callbacks, cancellation, and per-item completion handles belong to the caller
37
44
  *
38
45
  * Note: the name is somewhat of a misnomer as this wraps `IterableQueueMapper`
39
46
  * but is not itself an `Iterable`.
@@ -66,7 +73,6 @@ class IterableQueueMapperSimple {
66
73
  this._done = this.discardResults();
67
74
  }
68
75
  async discardResults() {
69
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
70
76
  let item = await this._writer.next();
71
77
  while (item.done !== true) {
72
78
  // Just discard all the results
@@ -85,7 +91,7 @@ class IterableQueueMapperSimple {
85
91
  return NoResult;
86
92
  }
87
93
  /**
88
- * Accumulated errors from background `mappers`s
94
+ * Accumulated errors from the worker callback.
89
95
  *
90
96
  * @remarks
91
97
  *
@@ -100,34 +106,34 @@ class IterableQueueMapperSimple {
100
106
  return this._errors;
101
107
  }
102
108
  /**
103
- * Accept a request for sending in the background if a concurrency slot is available.
104
- * Else, do not return until a concurrency slot is freed up.
105
- * This provides concurrency background writes with backpressure to prevent
106
- * the caller from getting too far ahead.
109
+ * Accept an input for the worker callback, waiting until it can be accepted.
110
+ * Resolves on acceptance, rather than completion of this item's work.
111
+ * Await each enqueue for producer backpressure.
107
112
  *
108
- * MUST await `onIdle` for background `mappers`s to finish
109
- * @param item
113
+ * After the last enqueue, await `onIdle()` to close input and finish accepted work.
114
+ * @param item Input for the worker callback
110
115
  */
111
116
  async enqueue(item) {
112
- // Return immediately or wait for a slot to free up in the background writer
117
+ // Return immediately or wait for the underlying mapping queue to accept the input
113
118
  await this._writer.enqueue(item);
114
119
  }
115
120
  /**
116
- * Wait for all background `mapper`s to finish.
117
- * MUST be called before exit to ensure no lost writes.
121
+ * Permanently close input and wait for all accepted work to finish.
122
+ * Call after the last awaited enqueue. Subsequent enqueues reject.
123
+ * Worker failures are available in `errors` instead of rejecting this wait.
118
124
  */
119
125
  async onIdle() {
120
126
  if (this._isIdle)
121
127
  return;
122
- // Indicate that we're done writing requests
128
+ // Indicate that no more inputs will be enqueued
123
129
  this._writer.done();
124
130
  await this._done;
125
131
  this._isIdle = true;
126
132
  }
127
133
  /**
128
- * Indicates if all background `mapper`s have finished.
134
+ * Indicates whether final shutdown has completed.
129
135
  *
130
- * @returns true if .onIdle() has been called and finished all background writes
136
+ * @returns true after `onIdle()` has finished all accepted work and closed input
131
137
  */
132
138
  get isIdle() {
133
139
  return this._isIdle;
@@ -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;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
+ {"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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;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,IAAI,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC1B,+BAA+B;YAC/B,oEAAoE;YACpE,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;QACnC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,MAAM,CAAC,IAAa,EAAE,KAAa;QAC/C,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAChC,8DAA8D;QAChE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACrC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,OAAO,CAAC,IAAa;QAChC,kFAAkF;QAClF,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,MAAM;QACjB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QAEzB,gDAAgD;QAChD,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;AArGD,8DAqGC"}
@@ -1,6 +1,6 @@
1
1
  import { IterableMapperOptions, Mapper } from './iterable-mapper';
2
2
  /**
3
- * Options for IterableQueueMapper
3
+ * Options for `IterableQueueMapper`, also exported as `MappingQueueOptions`.
4
4
  */
5
5
  export type IterableQueueMapperOptions = IterableMapperOptions;
6
6
  /**
@@ -9,12 +9,16 @@ export type IterableQueueMapperOptions = IterableMapperOptions;
9
9
  * of `maxUnread` size, before being iterated / read by the caller.
10
10
  * The `enqueue` method will block if the queue is full, until an item is read.
11
11
  *
12
+ * Also exported as `MappingQueue`, with the same constructor and instance types.
13
+ * Each input uses the same callback supplied at construction; results are exposed
14
+ * through the async iterator as mapping completes.
15
+ *
12
16
  * @remarks
13
17
  *
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
+ * ### Typical Use Cases
19
+ * - Enqueuing capability probes or metadata lookups as inputs become available
20
+ * - Sending items to an async I/O destination and consuming its acknowledgements
21
+ * - Consuming mapped results in a subsequent step (if results can be discarded, use `IterableQueueMapperSimple` / `WorkerQueue`)
18
22
  * - Prevents the producer from racing ahead of the consumer if `maxUnread` is reached
19
23
  *
20
24
  * ### Error Handling
@@ -33,8 +37,10 @@ export type IterableQueueMapperOptions = IterableMapperOptions;
33
37
  * ### Usage
34
38
  * - Items are added to the queue via the `await enqueue()` method
35
39
  * - 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
40
+ * - Produce inputs and consume results concurrently so the result buffer can drain
41
+ * - Call `done()` after the last awaited enqueue, then finish consuming the iterator
42
+ * - `enqueue()` confirms acceptance of an input; `done()` closes input without waiting for work to finish
43
+ * - Await each enqueue for producer backpressure; unawaited calls can accumulate pending inputs
38
44
  *
39
45
  * @category Enqueue Input
40
46
  *
@@ -62,7 +68,9 @@ export declare class IterableQueueMapper<Element, NewElement> implements AsyncIt
62
68
  */
63
69
  next(): Promise<IteratorResult<NewElement>>;
64
70
  /**
65
- * Add an item to the queue, wait if the queue is full.
71
+ * Add an item to the queue, waiting until it can be accepted.
72
+ * Resolves on acceptance, rather than completion of the mapper for this item.
73
+ * Await each enqueue while consuming results concurrently for producer backpressure.
66
74
  *
67
75
  * @param item Element to add
68
76
  */
@@ -70,7 +78,8 @@ export declare class IterableQueueMapper<Element, NewElement> implements AsyncIt
70
78
  /**
71
79
  * Indicate that no more items will be enqueued.
72
80
  *
73
- * This releases all readers blocked on `enqueue`
81
+ * Call after the last awaited enqueue. Finish consuming the async iterator
82
+ * to wait for mapped results; this method does not wait for processing to finish.
74
83
  */
75
84
  done(): void;
76
85
  }
@@ -12,12 +12,16 @@ const iterable_queue_1 = require("./iterable-queue");
12
12
  * of `maxUnread` size, before being iterated / read by the caller.
13
13
  * The `enqueue` method will block if the queue is full, until an item is read.
14
14
  *
15
+ * Also exported as `MappingQueue`, with the same constructor and instance types.
16
+ * Each input uses the same callback supplied at construction; results are exposed
17
+ * through the async iterator as mapping completes.
18
+ *
15
19
  * @remarks
16
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
+ * ### Typical Use Cases
22
+ * - Enqueuing capability probes or metadata lookups as inputs become available
23
+ * - Sending items to an async I/O destination and consuming its acknowledgements
24
+ * - Consuming mapped results in a subsequent step (if results can be discarded, use `IterableQueueMapperSimple` / `WorkerQueue`)
21
25
  * - Prevents the producer from racing ahead of the consumer if `maxUnread` is reached
22
26
  *
23
27
  * ### Error Handling
@@ -36,8 +40,10 @@ const iterable_queue_1 = require("./iterable-queue");
36
40
  * ### Usage
37
41
  * - Items are added to the queue via the `await enqueue()` method
38
42
  * - 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
43
+ * - Produce inputs and consume results concurrently so the result buffer can drain
44
+ * - Call `done()` after the last awaited enqueue, then finish consuming the iterator
45
+ * - `enqueue()` confirms acceptance of an input; `done()` closes input without waiting for work to finish
46
+ * - Await each enqueue for producer backpressure; unawaited calls can accumulate pending inputs
41
47
  *
42
48
  * @category Enqueue Input
43
49
  *
@@ -72,7 +78,9 @@ class IterableQueueMapper {
72
78
  return this._iterableMapper.next();
73
79
  }
74
80
  /**
75
- * Add an item to the queue, wait if the queue is full.
81
+ * Add an item to the queue, waiting until it can be accepted.
82
+ * Resolves on acceptance, rather than completion of the mapper for this item.
83
+ * Await each enqueue while consuming results concurrently for producer backpressure.
76
84
  *
77
85
  * @param item Element to add
78
86
  */
@@ -82,7 +90,8 @@ class IterableQueueMapper {
82
90
  /**
83
91
  * Indicate that no more items will be enqueued.
84
92
  *
85
- * This releases all readers blocked on `enqueue`
93
+ * Call after the last awaited enqueue. Finish consuming the async iterator
94
+ * to wait for mapped results; this method does not wait for processing to finish.
86
95
  */
87
96
  done() {
88
97
  this._sourceIterable.done();
@@ -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,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"}
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;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;;;;;;OAMG;IACI,KAAK,CAAC,OAAO,CAAC,IAAa;QAChC,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;OAKG;IACI,IAAI;QACT,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC;IAC9B,CAAC;CACF;AAvDD,kDAuDC"}
@@ -1 +1 @@
1
- {"version":3,"file":"iterable-queue.js","sourceRoot":"","sources":["../../src/iterable-queue.ts"],"names":[],"mappings":";;;AAAA,qDAAuE;AAIvE;;;;GAIG;AACH,MAAa,aACX,SAAQ,8BAAsB;IAG9B;;;OAGG;IACH,YAAY,UAAgC,EAAE;QAC5C,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAEM,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,IAAI;QACf,6BAA6B;QAC7B,MAAM,IAAI,GAAwB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAEvD,IAAI,IAAI,KAAK,SAAS,EAAE;YACtB,yCAAyC;YACzC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;SACzC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;CACF;AAjCD,sCAiCC"}
1
+ {"version":3,"file":"iterable-queue.js","sourceRoot":"","sources":["../../src/iterable-queue.ts"],"names":[],"mappings":";;;AAAA,qDAAuE;AAIvE;;;;GAIG;AACH,MAAa,aACX,SAAQ,8BAAsB;IAG9B;;;OAGG;IACH,YAAY,UAAgC,EAAE;QAC5C,KAAK,CAAC,OAAO,CAAC,CAAC;IACjB,CAAC;IAEM,CAAC,MAAM,CAAC,aAAa,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACI,KAAK,CAAC,IAAI;QACf,6BAA6B;QAC7B,MAAM,IAAI,GAAwB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAEvD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,yCAAyC;YACzC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC1C,CAAC;QAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACtC,CAAC;CACF;AAjCD,sCAiCC"}
@@ -1 +1 @@
1
- {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/queue.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,kGAAkG;AAClG,EAAE;;;AAEF;;;;GAIG;AACH,MAAa,KAAK;IAAlB;QACU,WAAM,GAA2B,EAAE,CAAC;QACpC,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;IAsBpB,CAAC;IApBC,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,0CAA0C;IACnC,OAAO,CAAC,OAAU;QACvB,IAAI,OAAO,KAAK,SAAS,EAAE;YACzB,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;SACnD;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACtC,CAAC;IAED,yCAAyC;IAClC,OAAO;QACZ,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAEhD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACjC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAzBD,sBAyBC"}
1
+ {"version":3,"file":"queue.js","sourceRoot":"","sources":["../../src/queue.ts"],"names":[],"mappings":";AAAA,EAAE;AACF,kGAAkG;AAClG,EAAE;;;AAEF;;;;GAIG;AACH,MAAa,KAAK;IAAlB;QACU,WAAM,GAA2B,EAAE,CAAC;QACpC,UAAK,GAAG,CAAC,CAAC;QACV,UAAK,GAAG,CAAC,CAAC;IAsBpB,CAAC;IApBC,IAAW,MAAM;QACf,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,0CAA0C;IACnC,OAAO,CAAC,OAAU;QACvB,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC;IACtC,CAAC;IAED,yCAAyC;IAClC,OAAO;QACZ,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAEhD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACjC,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AAzBD,sBAyBC"}
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@shutterstock/p-map-iterable",
3
- "version": "1.1.1",
4
- "description": "Set of classes used for async prefetching with backpressure (IterableMapper) and async flushing with backpressure (IterableQueueMapper, IterableQueueMapperSimple)",
3
+ "version": "1.2.0-prerelease.1",
4
+ "packageManager": "pnpm@12.7.0",
5
+ "description": "Concurrent mapping and queued background work with backpressure, streaming results, and collected errors",
5
6
  "main": "dist/src/index.js",
6
7
  "types": "dist/src/index.d.ts",
7
8
  "publishConfig": {
@@ -24,14 +25,15 @@
24
25
  "AsyncIterator"
25
26
  ],
26
27
  "scripts": {
27
- "build": "tsc --build tsconfig.json && echo 'examples/\n*.tsbuildinfo' > dist/.npmignore",
28
+ "build": "tsc --build tsconfig.json && echo 'examples/\n*.tsbuildinfo\n*.test.*\n*.d.ts.map' > dist/.npmignore",
28
29
  "build:docs": "typedoc src/index.ts",
29
30
  "example:iterable-mapper": "ts-node -r tsconfig-paths/register examples/iterable-mapper.ts",
30
31
  "example:iterable-queue-mapper": "ts-node -r tsconfig-paths/register examples/iterable-queue-mapper.ts",
31
32
  "example:iterable-queue-mapper-simple": "ts-node -r tsconfig-paths/register examples/iterable-queue-mapper-simple.ts",
33
+ "example:semantic-aliases": "ts-node -r tsconfig-paths/register examples/semantic-aliases.ts",
32
34
  "test": "jest",
33
- "lint": "eslint ./ --ext .ts --ext .tsx",
34
- "lint-and-fix": "eslint ./ --ext .ts --ext .tsx --fix"
35
+ "lint": "eslint .",
36
+ "lint-and-fix": "eslint . --fix"
35
37
  },
36
38
  "files": [
37
39
  "dist/",
@@ -44,24 +46,28 @@
44
46
  },
45
47
  "license": "MIT",
46
48
  "dependencies": {
47
- "aggregate-error": "^3.0.0"
49
+ "aggregate-error": "^3.1.0"
48
50
  },
49
51
  "peerDependencies": {
50
- "aggregate-error": "^3.0.0"
52
+ "aggregate-error": "^3.1.0"
51
53
  },
52
54
  "devDependencies": {
53
- "@types/jest": "29.5.2",
54
- "@typescript-eslint/eslint-plugin": "^5.13.0",
55
- "@typescript-eslint/parser": "^5.13.0",
56
- "eslint": "^7.15.0",
57
- "eslint-config-prettier": "^7.0.0",
58
- "eslint-plugin-prettier": "^3.2.0",
59
- "jest": "29.5.0",
60
- "prettier": "^2.2.1",
61
- "ts-jest": "29.1.0",
62
- "ts-node": "10.9.1",
55
+ "@eslint/js": "^10.0.1",
56
+ "@types/jest": "30.0.0",
57
+ "@types/node": "^26.6.3",
58
+ "@typescript-eslint/eslint-plugin": "^8.70.1",
59
+ "@typescript-eslint/parser": "^8.70.1",
60
+ "eslint": "^10.11.0",
61
+ "eslint-config-prettier": "^10.1.8",
62
+ "eslint-plugin-prettier": "^5.5.6",
63
+ "globals": "^17.12.0",
64
+ "jest": "30.5.2",
65
+ "lcov-parse": "1.0.0",
66
+ "prettier": "^3.9.9",
67
+ "ts-jest": "29.4.14",
68
+ "ts-node": "10.9.2",
63
69
  "tsconfig-paths": "4.2.0",
64
- "typedoc": "^0.24.8",
65
- "typescript": "5.1.3"
70
+ "typedoc": "^0.28.20",
71
+ "typescript": "6.0.3"
66
72
  }
67
73
  }
@@ -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,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=blocking-queue.test.d.ts.map
@@ -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(Math.ceil(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 = Math.ceil(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