time-queues 1.3.0 → 1.3.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/llms.txt ADDED
@@ -0,0 +1,95 @@
1
+ # time-queues
2
+
3
+ > Lightweight async task scheduling and concurrency control for JavaScript: schedulers, idle/frame/limited queues, throttle, debounce, batch, page lifecycle, random delays.
4
+
5
+ - NPM: https://npmjs.org/package/time-queues
6
+ - GitHub: https://github.com/uhop/time-queues
7
+ - Wiki: https://github.com/uhop/time-queues/wiki
8
+ - License: BSD-3-Clause
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install time-queues
14
+ ```
15
+
16
+ ## Quick start
17
+
18
+ ```js
19
+ import sleep from 'time-queues/sleep.js';
20
+ import {Scheduler, repeat} from 'time-queues/Scheduler.js';
21
+ import {batch} from 'time-queues/batch.js';
22
+
23
+ // Simple delay
24
+ await sleep(1000);
25
+
26
+ // Run a task every 5 seconds
27
+ const scheduler = new Scheduler();
28
+ scheduler.enqueue(repeat(({task, scheduler}) => {
29
+ console.log('tick');
30
+ }, 5000), 5000);
31
+
32
+ // Fetch URLs, max 3 at a time
33
+ const results = await batch(
34
+ urls.map(url => () => fetch(url).then(r => r.json())),
35
+ 3
36
+ );
37
+ ```
38
+
39
+ ## Modules
40
+
41
+ ### Queues
42
+
43
+ - **Scheduler** (`time-queues/Scheduler.js`) — time-based task scheduling with delays, dates, and repeats. Extends MicroTaskQueue. Uses a min-heap. Exports: `Scheduler`, `Task`, `repeat(fn, delay)`, `scheduler` (global instance).
44
+ - **IdleQueue** (`time-queues/IdleQueue.js`) — run tasks during browser idle periods via `requestIdleCallback()`. Extends ListQueue. Exports: `IdleQueue`, `idleQueue` (global instance), `defer(fn)`.
45
+ - **FrameQueue** (`time-queues/FrameQueue.js`) — run tasks in animation frames via `requestAnimationFrame()`. Extends ListQueue. Exports: `FrameQueue`, `frameQueue` (global instance).
46
+ - **LimitedQueue** (`time-queues/LimitedQueue.js`) — concurrency-controlled async queue. Extends ListQueue. Exports: `LimitedQueue`, `Task`.
47
+ - **PageWatcher** (`time-queues/PageWatcher.js`) — react to page lifecycle changes (active, passive, hidden, frozen, terminated). Extends ListQueue. Exports: `PageWatcher`, `watchStates(states, fn)`, `pageWatcher` (global instance).
48
+
49
+ ### Utility functions
50
+
51
+ - **sleep** (`time-queues/sleep.js`) — `sleep(ms | Date): Promise<void>`. Promise-based delay.
52
+ - **defer** (`time-queues/defer.js`) — `defer(fn): void`. Execute on next tick via `requestIdleCallback`/`setImmediate`/`setTimeout`. Also exports `scheduleDefer(fn): Promise`.
53
+ - **throttle** (`time-queues/throttle.js`) — `throttle(fn, ms): fn`. Rate-limit: execute immediately, ignore calls until timeout expires.
54
+ - **debounce** (`time-queues/debounce.js`) — `debounce(fn, ms): fn`. Delay until input stabilizes.
55
+ - **sample** (`time-queues/sample.js`) — `sample(fn, ms): fn`. Execute at regular intervals with last seen args.
56
+ - **audit** (`time-queues/audit.js`) — `audit(fn, ms): fn`. Collect then execute after delay with last seen args.
57
+ - **batch** (`time-queues/batch.js`) — `batch(fns, limit?): Promise<results[]>`. Run async operations with concurrency limit (default: 4).
58
+
59
+ ### Supporting classes
60
+
61
+ - **Throttler** (`time-queues/Throttler.js`) — key-based rate limiting with vacuum cleanup. Methods: `getDelay(key)`, `wait(key)`, `startVacuum()`, `stopVacuum()`.
62
+ - **Retainer** (`time-queues/Retainer.js`) — resource lifecycle management with reference counting. Methods: `get(): Promise<value>`, `release(): Promise<void>`.
63
+ - **Counter** (`time-queues/Counter.js`) — numeric counter with async waiting. Methods: `increment()`, `decrement()`, `advance(delta)`, `waitForZero()`, `waitFor(target)`.
64
+ - **CancelTaskError** (`time-queues/CancelTaskError.js`) — `Error` subclass for task cancellation signals.
65
+
66
+ ### Base classes
67
+
68
+ - **MicroTask** (`time-queues/MicroTask.js`) — base task unit with lazy promise creation. Methods: `makePromise()`, `resolve(value)`, `cancel(error)`.
69
+ - **MicroTaskQueue** (`time-queues/MicroTaskQueue.js`) — abstract queue base class. Methods: `enqueue(fn)`, `dequeue(task)`, `schedule(fn)`, `clear()`, `pause()`, `resume()`.
70
+ - **ListQueue** (`time-queues/ListQueue.js`) — linked-list queue implementation extending MicroTaskQueue. Adds `startQueue()` lifecycle.
71
+
72
+ ### Random utilities
73
+
74
+ - **random-dist** (`time-queues/random-dist.js`) — `uniform(min, max)`, `normal(mean, stdDev, skewness?)`, `expo(lambda)`, `pareto(min, alpha)`.
75
+ - **random-sleep** (`time-queues/random-sleep.js`) — `randomUniformSleep(min, max)`, `randomNormalSleep(mean, stdDev)`, `randomExpoSleep(lambda, scale)`, `randomParetoSleep(min, ratio)`, `randomSleep(max)`. Each returns `() => Promise<void>`.
76
+
77
+ ### Page load helpers
78
+
79
+ - **whenDomLoaded** (`time-queues/when-dom-loaded.js`) — `whenDomLoaded(fn)`. Also exports `scheduleWhenDomLoaded(fn): Promise`, `remove(fn): boolean`.
80
+ - **whenLoaded** (`time-queues/when-loaded.js`) — `whenLoaded(fn)`. Also exports `scheduleWhenLoaded(fn): Promise`, `remove(fn): boolean`.
81
+
82
+ ## Key concepts
83
+
84
+ - All modules are **ESM** with `import ... from 'time-queues/<module>.js'`.
85
+ - **Inheritance**: `MicroTaskQueue` → `ListQueue` → `IdleQueue`/`FrameQueue`/`LimitedQueue`/`PageWatcher`. `Scheduler` extends `MicroTaskQueue` directly.
86
+ - **Lazy promises** — only created when `.makePromise()` is called or via `schedule()`.
87
+ - **Clean cancellation** — all tasks support cancellation via `CancelTaskError`.
88
+ - **Graceful degradation** — feature detection for browser APIs, works in Node.js/Bun/Deno.
89
+ - **TypeScript** — built-in `.d.ts` declarations for all modules.
90
+
91
+ ## Links
92
+
93
+ - Docs: https://github.com/uhop/time-queues/wiki
94
+ - npm: https://www.npmjs.com/package/time-queues
95
+ - Full LLM reference: https://github.com/uhop/time-queues/blob/master/llms-full.txt
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "time-queues",
3
- "version": "1.3.0",
4
- "description": "Time queues to organize multitasking and scheduled tasks.",
3
+ "version": "1.3.2",
4
+ "description": "Lightweight async task scheduling and concurrency control: schedulers, idle/frame/limited queues, throttle, debounce, batch, page lifecycle, random delays. Browsers, Node.js, Deno, Bun.",
5
5
  "type": "module",
6
6
  "types": "./src/index.d.ts",
7
7
  "exports": {
@@ -21,8 +21,14 @@
21
21
  "ts-test": "tape6 --flags FO '/ts-tests/test-*.*ts'",
22
22
  "ts-test:bun": "tape6-bun --flags FO '/ts-tests/test-*.*ts'",
23
23
  "ts-test:deno": "tape6-deno --flags FO '/ts-tests/test-*.*ts'",
24
- "lint": "prettier --check src/ tests/ wiki/",
25
- "lint:fix": "prettier --write src/ tests/ wiki/",
24
+ "ts-test:proc": "tape6-proc --flags FO '/ts-tests/test-*.*ts'",
25
+ "ts-test:proc:bun": "bun run `tape6-proc --self` --flags FO '/ts-tests/test-*.*ts'",
26
+ "ts-test:proc:deno": "deno run -A `tape6-proc --self` --flags FO -r -A '/ts-tests/test-*.*ts'",
27
+ "ts-test:seq": "tape6-seq --flags FO '/ts-tests/test-*.*ts'",
28
+ "ts-test:seq:bun": "bun run `tape6-seq --self` --flags FO '/ts-tests/test-*.*ts'",
29
+ "ts-test:seq:deno": "deno run -A `tape6-seq --self` --flags FO '/ts-tests/test-*.*ts'",
30
+ "lint": "prettier --check .",
31
+ "lint:fix": "prettier --write .",
26
32
  "start": "tape6-server --trace"
27
33
  },
28
34
  "repository": {
@@ -30,9 +36,25 @@
30
36
  "url": "git+ssh://git@github.com/uhop/time-queues.git"
31
37
  },
32
38
  "keywords": [
39
+ "scheduler",
40
+ "task-queue",
41
+ "async-queue",
42
+ "concurrency",
43
+ "throttle",
44
+ "debounce",
45
+ "rate-limit",
46
+ "batch",
47
+ "sleep",
48
+ "defer",
49
+ "idle-queue",
50
+ "requestIdleCallback",
51
+ "requestAnimationFrame",
52
+ "page-lifecycle",
33
53
  "timer",
34
54
  "time",
35
- "queue"
55
+ "queue",
56
+ "esm",
57
+ "typescript"
36
58
  ],
37
59
  "author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (https://www.lazutkin.com/)",
38
60
  "funding": "https://github.com/sponsors/uhop",
@@ -40,15 +62,24 @@
40
62
  "bugs": {
41
63
  "url": "https://github.com/uhop/time-queues/issues"
42
64
  },
65
+ "github": "https://github.com/uhop/time-queues",
43
66
  "homepage": "https://github.com/uhop/time-queues#readme",
67
+ "llms": "https://raw.githubusercontent.com/uhop/time-queues/master/llms.txt",
68
+ "llmsFull": "https://raw.githubusercontent.com/uhop/time-queues/master/llms-full.txt",
44
69
  "files": [
45
70
  "/src",
46
71
  "LICENSE",
47
- "README.md"
72
+ "README.md",
73
+ "llms.txt",
74
+ "llms-full.txt"
48
75
  ],
49
76
  "tape6": {
50
77
  "tests": [
51
- "/tests/test-*.*js"
78
+ "/tests/test-*.js",
79
+ "/tests/test-*.mjs"
80
+ ],
81
+ "cli": [
82
+ "/tests/test-*.cjs"
52
83
  ],
53
84
  "importmap": {
54
85
  "imports": {
@@ -59,12 +90,13 @@
59
90
  }
60
91
  },
61
92
  "devDependencies": {
62
- "@types/node": "^25.2.3",
63
- "tape-six": "^1.7.0",
64
- "tape-six-proc": "^1.2.2",
93
+ "@types/node": "^25.5.0",
94
+ "prettier": "^3.8.1",
95
+ "tape-six": "^1.7.12",
96
+ "tape-six-proc": "^1.2.7",
65
97
  "typescript": "^5.9.3"
66
98
  },
67
99
  "dependencies": {
68
- "list-toolkit": "^2.2.6"
100
+ "list-toolkit": "^2.3.2"
69
101
  }
70
102
  }
@@ -2,7 +2,8 @@
2
2
  * A cancellation error that is thrown when a microtask is canceled.
3
3
  */
4
4
  export declare class CancelTaskError extends Error {
5
- constructor(message: string = 'Task was canceled', options?: ErrorOptions);
5
+ name: 'CancelTaskError';
6
+ constructor(message?: string, options?: ErrorOptions);
6
7
  }
7
8
 
8
9
  export default CancelTaskError;
@@ -1,7 +1,5 @@
1
1
  // @ts-self-types="./CancelTaskError.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  export class CancelTaskError extends Error {
6
4
  constructor(message = 'Task was canceled', options) {
7
5
  super(message, options);
package/src/Counter.d.ts CHANGED
@@ -22,7 +22,7 @@ export declare class Counter {
22
22
  * Sets the counter to a specific value.
23
23
  * @param value The new value for the counter.
24
24
  */
25
- set value(value: number): void;
25
+ set value(value: number);
26
26
 
27
27
  /**
28
28
  * Increments the counter.
package/src/Counter.js CHANGED
@@ -1,7 +1,5 @@
1
1
  // @ts-self-types="./Counter.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  export class Counter {
6
4
  constructor(initial = 0) {
7
5
  this.count = initial;
@@ -1,4 +1,4 @@
1
- import {ListQueue, Task} from './ListQueue';
1
+ import {ListQueue, Task} from './ListQueue.js';
2
2
 
3
3
  /**
4
4
  * A queue based on [requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame).
@@ -33,7 +33,7 @@ export declare class FrameQueue extends ListQueue {
33
33
  * @param fn The function to execute.
34
34
  * @returns The task object.
35
35
  */
36
- enqueue(fn: ({timeStamp: number, task: Task, queue: FrameQueue}) => unknown): Task;
36
+ enqueue(fn: (arg: {timeStamp: number; task: Task; queue: FrameQueue}) => unknown): Task;
37
37
 
38
38
  /**
39
39
  * Dequeues a task.
@@ -44,11 +44,11 @@ export declare class FrameQueue extends ListQueue {
44
44
 
45
45
  /**
46
46
  * Schedules a task to run in the next frame.
47
- * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with function's arguments. Otherwise, it is resolved with the function's return value.
47
+ * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with the function's arguments. Otherwise, it is resolved with the function's return value.
48
48
  * @returns The task object.
49
49
  */
50
50
  schedule(
51
- fn: (({timeStamp: number, task: Task, queue: FrameQueue}) => unknown) | null | undefined
51
+ fn: ((arg: {timeStamp: number; task: Task; queue: FrameQueue}) => unknown) | null | undefined
52
52
  ): Task;
53
53
 
54
54
  /**
@@ -82,4 +82,4 @@ export declare class FrameQueue extends ListQueue {
82
82
  */
83
83
  export const frameQueue: FrameQueue;
84
84
 
85
- export default FrameQueue;
85
+ export default frameQueue;
package/src/FrameQueue.js CHANGED
@@ -1,7 +1,5 @@
1
1
  // @ts-self-types="./FrameQueue.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  import List from 'list-toolkit/list.js';
6
4
  import ListQueue from './ListQueue.js';
7
5
 
@@ -1,4 +1,4 @@
1
- import {ListQueue, Task} from './ListQueue';
1
+ import {ListQueue, Task} from './ListQueue.js';
2
2
 
3
3
  /**
4
4
  * A queue based on [requestIdleCallback()](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback).
@@ -20,7 +20,7 @@ export declare class IdleQueue extends ListQueue {
20
20
  /**
21
21
  * The options passed to `requestIdleCallback()`.
22
22
  */
23
- options: IdleCallbackOptions | undefined;
23
+ options: IdleRequestOptions | undefined;
24
24
 
25
25
  /**
26
26
  * Creates a new idle queue.
@@ -28,7 +28,7 @@ export declare class IdleQueue extends ListQueue {
28
28
  * @param timeoutBatchInMs The timeout batch size in milliseconds.
29
29
  * @param options The options passed to `requestIdleCallback()`.
30
30
  */
31
- constructor(paused?: boolean, timeoutBatchInMs?: number, options?: IdleCallbackOptions);
31
+ constructor(paused?: boolean, timeoutBatchInMs?: number, options?: IdleRequestOptions);
32
32
 
33
33
  /**
34
34
  * Whether the queue is empty.
@@ -40,7 +40,7 @@ export declare class IdleQueue extends ListQueue {
40
40
  * @param fn The function to execute.
41
41
  * @returns The task object.
42
42
  */
43
- enqueue(fn: ({deadline: IdleDeadline, task: Task, queue: IdleQueue}) => unknown): Task;
43
+ enqueue(fn: (arg: {deadline: IdleDeadline; task: Task; queue: IdleQueue}) => unknown): Task;
44
44
 
45
45
  /**
46
46
  * Dequeues a task.
@@ -51,11 +51,14 @@ export declare class IdleQueue extends ListQueue {
51
51
 
52
52
  /**
53
53
  * Schedules a task to run in the next idle period.
54
- * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with function's arguments. Otherwise, it is resolved with the function's return value.
54
+ * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with the function's arguments. Otherwise, it is resolved with the function's return value.
55
55
  * @returns The task object.
56
56
  */
57
57
  schedule(
58
- fn: (({deadline: IdleDeadline, task: Task, queue: IdleQueue}) => unknown) | null | undefined
58
+ fn:
59
+ | ((arg: {deadline: IdleDeadline; task: Task; queue: IdleQueue}) => unknown)
60
+ | null
61
+ | undefined
59
62
  ): Task;
60
63
 
61
64
  /**
@@ -93,7 +96,7 @@ export const idleQueue: IdleQueue;
93
96
  * A function that schedules a task to run in the next idle period.
94
97
  */
95
98
  export const defer: (
96
- fn: ({deadline: IdleDeadline, task: Task, queue: IdleQueue}) => unknown
99
+ fn: (arg: {deadline: IdleDeadline; task: Task; queue: IdleQueue}) => unknown
97
100
  ) => Task;
98
101
 
99
- export default IdleQueue;
102
+ export default idleQueue;
package/src/IdleQueue.js CHANGED
@@ -1,7 +1,5 @@
1
1
  // @ts-self-types="./IdleQueue.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  import List from 'list-toolkit/list.js';
6
4
  import ListQueue from './ListQueue.js';
7
5
 
@@ -1,4 +1,4 @@
1
- import {ListQueue, Task} from './ListQueue';
1
+ import {ListQueue, Task} from './ListQueue.js';
2
2
 
3
3
  export {Task};
4
4
 
@@ -15,7 +15,7 @@ export declare class LimitedQueue extends ListQueue {
15
15
  stopQueue: (() => void) | null;
16
16
 
17
17
  /**
18
- * Creates a new list queue.
18
+ * Creates a new limited queue.
19
19
  * @param limit The maximum number of tasks that can be run in parallel.
20
20
  * @param paused Whether the queue should start paused.
21
21
  */
@@ -33,7 +33,7 @@ export declare class LimitedQueue extends ListQueue {
33
33
 
34
34
  /**
35
35
  * Set the maximum number of tasks that can be run in parallel.
36
- * @param limit The new maximum number of tasks that can be run in parallel. It can dynamically add more tasks if the current number of tasks is less than the new limit.
36
+ * @param limit The new maximum number of tasks that can be run in parallel. Setting a higher limit may immediately start additional tasks.
37
37
  */
38
38
  set taskLimit(limit: number);
39
39
 
@@ -48,7 +48,7 @@ export declare class LimitedQueue extends ListQueue {
48
48
  get isIdle(): boolean;
49
49
 
50
50
  /**
51
- * Wait for queue to become idle.
51
+ * Waits for the queue to become idle.
52
52
  * @returns A promise that resolves when the queue becomes idle. If the queue is already idle, the promise is resolved immediately.
53
53
  */
54
54
  waitForIdle(): Promise<void>;
@@ -58,7 +58,7 @@ export declare class LimitedQueue extends ListQueue {
58
58
  * @param fn The function to execute when the microtask is scheduled.
59
59
  * @returns The enqueued microtask.
60
60
  */
61
- enqueue(fn: () => unknown): Task;
61
+ enqueue(fn: (arg: {task: Task; queue: LimitedQueue}) => unknown): Task;
62
62
 
63
63
  /**
64
64
  * Dequeues a microtask.
@@ -69,10 +69,10 @@ export declare class LimitedQueue extends ListQueue {
69
69
 
70
70
  /**
71
71
  * Schedules a microtask.
72
- * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with function's arguments. Otherwise, it is resolved with the function's return value.
72
+ * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with the function's arguments. Otherwise, it is resolved with the function's return value.
73
73
  * @returns The task object.
74
74
  */
75
- schedule(fn: (() => unknown) | null | undefined): Task;
75
+ schedule(fn: ((arg: {task: Task; queue: LimitedQueue}) => unknown) | null | undefined): Task;
76
76
 
77
77
  /**
78
78
  * Clears the queue.
@@ -9,7 +9,7 @@ export class LimitedQueue extends ListQueue {
9
9
 
10
10
  constructor(limit, paused) {
11
11
  super(paused);
12
- this.#taskLimit = limit;
12
+ this.#taskLimit = Math.max(1, limit);
13
13
  this.#activeTasks = 0;
14
14
  this.#idleWaiters = [];
15
15
  }
@@ -1,6 +1,5 @@
1
- import {MicroTask} from './MicroTask';
2
- import {MicroTaskQueue} from './MicroTaskQueue';
3
- import {List} from 'list-toolkit';
1
+ import {MicroTask} from './MicroTask.js';
2
+ import {MicroTaskQueue} from './MicroTaskQueue.js';
4
3
 
5
4
  /**
6
5
  * A list-based queue of microtasks that will be executed when scheduled.
@@ -34,7 +33,7 @@ export declare class ListQueue extends MicroTaskQueue {
34
33
  * @param fn The function to execute when the microtask is scheduled.
35
34
  * @returns The enqueued microtask.
36
35
  */
37
- enqueue(fn: () => unknown): MicroTask;
36
+ enqueue(fn: (...args: any[]) => unknown): MicroTask;
38
37
 
39
38
  /**
40
39
  * Dequeues a microtask.
@@ -45,10 +44,10 @@ export declare class ListQueue extends MicroTaskQueue {
45
44
 
46
45
  /**
47
46
  * Schedules a microtask.
48
- * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with function's arguments. Otherwise, it is resolved with the function's return value.
47
+ * @param fn The function to execute. If `undefined` or `null`, the task's promise will be resolved with the function's arguments. Otherwise, it is resolved with the function's return value.
49
48
  * @returns The task object.
50
49
  */
51
- schedule(fn: (() => unknown) | null | undefined): MicroTask;
50
+ schedule(fn: ((...args: any[]) => unknown) | null | undefined): MicroTask;
52
51
 
53
52
  /**
54
53
  * Clears the queue.
package/src/ListQueue.js CHANGED
@@ -1,14 +1,20 @@
1
1
  // @ts-self-types="./ListQueue.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  import List from 'list-toolkit/list.js';
6
4
  import MicroTaskQueue from './MicroTaskQueue.js';
7
5
 
6
+ /**
7
+ * ListQueue extends MicroTaskQueue with linked-list task storage.
8
+ * AI-NOTE: This is the concrete base class most specialized queues extend.
9
+ * Key pattern: startQueue() returns a stop function (or null if not started).
10
+ * @see IdleQueue, FrameQueue, LimitedQueue, Scheduler - All extend ListQueue
11
+ */
8
12
  export class ListQueue extends MicroTaskQueue {
9
13
  constructor(paused) {
10
14
  super(paused);
15
+ // AI-NOTE: Using list-toolkit List for O(1) push/pop operations
11
16
  this.list = new List();
17
+ // AI-NOTE: stopQueue holds the stop function returned by startQueue(), or null
12
18
  this.stopQueue = null;
13
19
  }
14
20
 
@@ -19,6 +25,7 @@ export class ListQueue extends MicroTaskQueue {
19
25
  pause() {
20
26
  if (!this.paused) {
21
27
  super.pause();
28
+ // AI-NOTE: Pattern: call stop function, then null it
22
29
  if (this.stopQueue) this.stopQueue = (this.stopQueue(), null);
23
30
  }
24
31
  return this;
@@ -27,6 +34,7 @@ export class ListQueue extends MicroTaskQueue {
27
34
  resume() {
28
35
  if (this.paused) {
29
36
  super.resume();
37
+ // AI-NOTE: Auto-start processing if tasks exist and not already running
30
38
  if (!this.list.isEmpty) {
31
39
  this.stopQueue = this.startQueue();
32
40
  }
@@ -37,6 +45,7 @@ export class ListQueue extends MicroTaskQueue {
37
45
  enqueue(fn) {
38
46
  const task = super.enqueue(fn);
39
47
  this.list.pushBack(task);
48
+ // AI-NOTE: Auto-start queue on first task if not paused and not running
40
49
  if (!this.paused && !this.stopQueue) this.stopQueue = this.startQueue();
41
50
  return task;
42
51
  }
@@ -44,6 +53,7 @@ export class ListQueue extends MicroTaskQueue {
44
53
  dequeue(task) {
45
54
  task.cancel();
46
55
  this.list.removeNode(task);
56
+ // AI-NOTE: Auto-stop queue when empty (unless paused)
47
57
  if (!this.paused && this.list.isEmpty && this.stopQueue)
48
58
  this.stopQueue = (this.stopQueue(), null);
49
59
  return this;
@@ -60,7 +70,12 @@ export class ListQueue extends MicroTaskQueue {
60
70
  return this;
61
71
  }
62
72
 
63
- // API to be overridden in subclasses
73
+ /**
74
+ * Start processing the queue - MUST be overridden by subclasses.
75
+ * AI-NOTE: This is the abstract method pattern - base returns null.
76
+ * Subclasses return a function that stops the processing.
77
+ * @returns {Function|null} Stop function or null if not started
78
+ */
64
79
  startQueue() {
65
80
  return null;
66
81
  }
@@ -5,7 +5,7 @@ export declare class MicroTask {
5
5
  /**
6
6
  * The function to execute when the microtask is scheduled.
7
7
  */
8
- fn: () => unknown;
8
+ fn: (...args: any[]) => unknown;
9
9
 
10
10
  /**
11
11
  * Whether the microtask has been canceled.
@@ -16,7 +16,7 @@ export declare class MicroTask {
16
16
  * Creates a new microtask.
17
17
  * @param fn The function to execute when the microtask is scheduled.
18
18
  */
19
- constructor(fn: () => unknown);
19
+ constructor(fn: (...args: any[]) => unknown);
20
20
 
21
21
  /**
22
22
  * Makes a promise that will be resolved when the microtask is executed.
@@ -31,6 +31,11 @@ export declare class MicroTask {
31
31
  */
32
32
  get promise(): Promise<unknown> | null;
33
33
 
34
+ /**
35
+ * Whether the microtask has been settled (resolved or canceled).
36
+ */
37
+ get settled(): boolean;
38
+
34
39
  /**
35
40
  * Resolves the microtask, if a promise is created.
36
41
  * @param value The value to resolve the microtask with.
package/src/MicroTask.js CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  import CancelTaskError from './CancelTaskError.js';
4
4
 
5
+ /**
6
+ * Base class for deferred task execution with lazy promise creation.
7
+ * AI-NOTE: Promises are created lazily via makePromise() - not in constructor.
8
+ * This allows tasks to be created without immediate promise overhead.
9
+ */
5
10
  export class MicroTask {
6
11
  #promise;
7
12
  #resolve;
@@ -9,17 +14,25 @@ export class MicroTask {
9
14
  #settled;
10
15
  constructor(fn) {
11
16
  this.fn = fn;
17
+ // AI-NOTE: Private fields initialized to null - lazy initialization pattern
12
18
  this.#promise = null;
13
19
  this.#resolve = null;
14
20
  this.#reject = null;
21
+ this.#settled = false;
15
22
  this.isCanceled = false;
16
23
  }
24
+ // AI-NOTE: Returns null until makePromise() is called - this is intentional
17
25
  get promise() {
18
26
  return this.#promise;
19
27
  }
20
28
  get settled() {
21
29
  return this.#settled;
22
30
  }
31
+ /**
32
+ * Creates the promise and resolution functions.
33
+ * AI-NOTE: Uses Promise.withResolvers() when available (modern environments),
34
+ * falls back to manual Promise constructor for broader compatibility.
35
+ */
23
36
  makePromise() {
24
37
  if (this.#promise) return this;
25
38
  if (typeof Promise.withResolvers == 'function') {
@@ -45,6 +58,10 @@ export class MicroTask {
45
58
  }
46
59
  return this;
47
60
  }
61
+ /**
62
+ * Cancel the task with optional error cause.
63
+ * AI-NOTE: Always rejects with CancelTaskError to distinguish from other errors.
64
+ */
48
65
  cancel(error) {
49
66
  this.isCanceled = true;
50
67
  if (this.#reject) {
@@ -1,4 +1,4 @@
1
- import MicroTask from './MicroTask';
1
+ import MicroTask from './MicroTask.js';
2
2
 
3
3
  /**
4
4
  * A queue of microtasks that will be executed when scheduled.
@@ -29,7 +29,7 @@ export declare class MicroTaskQueue {
29
29
  * @param fn The function to execute when the microtask is scheduled.
30
30
  * @returns The enqueued microtask.
31
31
  */
32
- enqueue(fn: () => unknown): MicroTask;
32
+ enqueue(fn: (...args: any[]) => unknown, ...args: unknown[]): MicroTask;
33
33
 
34
34
  /**
35
35
  * Dequeues a microtask from the queue.
@@ -42,11 +42,11 @@ export declare class MicroTaskQueue {
42
42
  /**
43
43
  * Schedules a microtask with a promise for execution.
44
44
  * This can be overridden in subclasses if more arguments are needed.
45
- * @param fn The function to execute when the microtask is scheduled, it can be an async function.
46
- * @param args Additional arguments to pass to `enqueue()`. It is there to accommodate custom implementations in subclasses.
45
+ * @param fn The function to execute when the microtask is scheduled. It can be an async function.
46
+ * @param args Additional arguments to pass to `enqueue()`. They are there to accommodate custom implementations in subclasses.
47
47
  * @returns The scheduled microtask.
48
48
  */
49
- schedule(fn: (() => unknown) | null | undefined, ...args: unknown[]): MicroTask;
49
+ schedule(fn: ((...args: any[]) => unknown) | null | undefined, ...args: unknown[]): MicroTask;
50
50
 
51
51
  /**
52
52
  * Clears all tasks from the queue.
@@ -1,14 +1,19 @@
1
1
  // @ts-self-types="./MicroTaskQueue.d.ts"
2
2
 
3
- 'use strict';
4
-
5
3
  import MicroTask from './MicroTask.js';
6
4
 
5
+ /**
6
+ * Base queue class for managing task lifecycle.
7
+ * AI-NOTE: This is an abstract base class - concrete implementations should extend
8
+ * ListQueue for actual task storage and processing.
9
+ * @see ListQueue - The primary class for queue implementations
10
+ */
7
11
  export class MicroTaskQueue {
8
12
  constructor(paused) {
9
13
  this.paused = Boolean(paused);
10
14
  }
11
15
  // API to be overridden in subclasses
16
+ // AI-NOTE: Base implementation returns true - subclasses override with actual logic
12
17
  get isEmpty() {
13
18
  return true;
14
19
  }
@@ -20,6 +25,11 @@ export class MicroTaskQueue {
20
25
  this.paused = false;
21
26
  return this;
22
27
  }
28
+ /**
29
+ * Enqueue a function for execution.
30
+ * AI-NOTE: Creates MicroTask but does NOT create promise automatically.
31
+ * Call task.makePromise() if promise access is needed.
32
+ */
23
33
  enqueue(fn) {
24
34
  const task = new MicroTask(fn);
25
35
  return task;
@@ -31,7 +41,11 @@ export class MicroTaskQueue {
31
41
  clear() {
32
42
  return this;
33
43
  }
34
- // Generic API
44
+ /**
45
+ * Schedule a function with automatic promise creation.
46
+ * AI-NOTE: This is the convenience method - it calls both enqueue() and makePromise().
47
+ * Returns a MicroTask with an active promise.
48
+ */
35
49
  schedule(fn, ...args) {
36
50
  fn ||= MicroTaskQueue.returnArgs;
37
51
  const task = this.enqueue(