time-queues 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,7 +17,20 @@ export declare type ThrottlerOptions = {
17
17
  };
18
18
 
19
19
  /**
20
- * A throttler that throttles the execution of tasks based on a key.
20
+ * A throttler that paces the execution of work based on a key.
21
+ *
22
+ * Despite the name, this is **rate-limiting / pacing**, not classical
23
+ * "drop excess" throttle. `Throttler` does not execute functions; it
24
+ * exposes `wait(key)` and the caller decides what to do once awaited.
25
+ * Because there is nothing for `Throttler` to drop, every call is honored
26
+ * — N rapid calls produce delays roughly `0, throttleTimeout,
27
+ * 2*throttleTimeout, …`, spacing the work out across time. Use it when
28
+ * you need every operation to run but no faster than `throttleTimeout`
29
+ * apart per key.
30
+ *
31
+ * If you want React/Lodash-style "fire-leading-edge-only-then-drop"
32
+ * semantics, wrap your callback with `throttle()` from this package
33
+ * instead.
21
34
  */
22
35
  export declare class Throttler implements ThrottlerOptions {
23
36
  /**
@@ -44,11 +57,7 @@ export declare class Throttler implements ThrottlerOptions {
44
57
  * Creates a new throttler.
45
58
  * @param options The options for the throttler.
46
59
  */
47
- constructor({
48
- throttleTimeout = 1_000,
49
- neverSeenTimeout = 0,
50
- vacuumPeriod = throttleTimeout * 3
51
- }: ThrottlerOptions = {});
60
+ constructor(options?: ThrottlerOptions);
52
61
 
53
62
  /**
54
63
  * Retrieves the last seen time for a key as a timestamp in milliseconds.
@@ -58,16 +67,20 @@ export declare class Throttler implements ThrottlerOptions {
58
67
  getLastSeen(key: unknown): number;
59
68
 
60
69
  /**
61
- * Retrieves the delay for a key.
70
+ * Retrieves the delay for a key and reserves the next slot.
71
+ * Each call extends the per-key queue: stored state advances by the returned
72
+ * delay, so the next call for the same key waits at least `throttleTimeout`
73
+ * past the slot just allocated. Returns the delay in milliseconds.
62
74
  * @param key The key to retrieve the delay for.
63
- * @returns The delay for the key in milliseconds.
75
+ * @returns The delay before this caller's slot opens, in milliseconds.
64
76
  */
65
77
  getDelay(key: unknown): number;
66
78
 
67
79
  /**
68
- * Waits for a key to be available.
80
+ * Waits until this caller's slot for `key` opens. See class docs for the
81
+ * pacing semantics — every call is queued, none are dropped.
69
82
  * @param key The key to wait for.
70
- * @returns A promise that resolves when the key is available.
83
+ * @returns A promise that resolves when the slot is available.
71
84
  */
72
85
  wait(key: unknown): Promise<void>;
73
86
 
package/src/Throttler.js CHANGED
@@ -3,6 +3,8 @@
3
3
  import sleep from './sleep.js';
4
4
 
5
5
  export class Throttler {
6
+ #handle = null;
7
+
6
8
  constructor({
7
9
  throttleTimeout = 1_000,
8
10
  neverSeenTimeout = 0,
@@ -12,7 +14,6 @@ export class Throttler {
12
14
  this.neverSeenTimeout = neverSeenTimeout;
13
15
  this.vacuumPeriod = vacuumPeriod;
14
16
  this.lastSeen = new Map();
15
- this.handle = null;
16
17
  if (this.vacuumPeriod) this.startVacuum();
17
18
  }
18
19
 
@@ -38,7 +39,7 @@ export class Throttler {
38
39
  }
39
40
 
40
41
  get isVacuuming() {
41
- return !!this.handle;
42
+ return !!this.#handle;
42
43
  }
43
44
 
44
45
  vacuum() {
@@ -51,18 +52,18 @@ export class Throttler {
51
52
  }
52
53
 
53
54
  startVacuum() {
54
- if (this.handle) return this;
55
- this.handle = setInterval(() => {
55
+ if (this.#handle) return this;
56
+ this.#handle = setInterval(() => {
56
57
  this.vacuum();
57
58
  }, this.vacuumPeriod);
58
- if (this.handle.unref) this.handle.unref();
59
+ if (this.#handle.unref) this.#handle.unref();
59
60
  return this;
60
61
  }
61
62
 
62
63
  stopVacuum() {
63
- if (!this.handle) return this;
64
- clearInterval(this.handle);
65
- this.handle = null;
64
+ if (!this.#handle) return this;
65
+ clearInterval(this.#handle);
66
+ this.#handle = null;
66
67
  return this;
67
68
  }
68
69
  }
package/src/audit.js CHANGED
@@ -4,7 +4,7 @@ export const audit = (fn, ms) => {
4
4
  let handle = null,
5
5
  lastSeenArgs = null;
6
6
  return (...args) => {
7
- lastSeenArgs = [...args];
7
+ lastSeenArgs = args;
8
8
  if (handle) return;
9
9
  handle = setTimeout(() => {
10
10
  handle = null;
package/src/defer.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // @ts-self-types="./defer.d.ts"
2
2
 
3
+ /** @type {(...args: any[]) => any} */
3
4
  let deferImplementation = setTimeout;
4
5
 
5
6
  if (typeof requestIdleCallback == 'function') {
package/src/index.d.ts CHANGED
@@ -1,29 +1,27 @@
1
- declare module 'time-queues' {
2
- export * from './audit';
3
- export * from './batch';
4
- export * from './debounce';
5
- export * from './defer';
6
- export * from './sample';
7
- export * from './sleep';
8
- export * from './throttle';
1
+ export * from './audit.js';
2
+ export * from './batch.js';
3
+ export * from './debounce.js';
4
+ export * from './defer.js';
5
+ export * from './sample.js';
6
+ export * from './sleep.js';
7
+ export * from './throttle.js';
9
8
 
10
- export * from './CancelTaskError';
11
- export * from './MicroTask';
12
- export * from './MicroTaskQueue';
13
- export * from './LimitedQueue';
14
- export * from './ListQueue';
15
- export * from './FrameQueue';
16
- export * from './IdleQueue';
9
+ export * from './CancelTaskError.js';
10
+ export * from './MicroTask.js';
11
+ export * from './MicroTaskQueue.js';
12
+ export * from './LimitedQueue.js';
13
+ export * from './ListQueue.js';
14
+ export * from './FrameQueue.js';
15
+ export {IdleQueue, idleQueue} from './IdleQueue.js';
17
16
 
18
- export * from './Counter';
19
- export * from './PageWatcher';
20
- export * from './Retainer';
21
- export * from './Scheduler';
22
- export * from './Throttler';
17
+ export * from './Counter.js';
18
+ export * from './PageWatcher.js';
19
+ export * from './Retainer.js';
20
+ export {Task as SchedulerTask, Scheduler, repeat, scheduler} from './Scheduler.js';
21
+ export * from './Throttler.js';
23
22
 
24
- export * from './random-dist';
25
- export * from './random-sleep';
23
+ export * from './random-dist.js';
24
+ export * from './random-sleep.js';
26
25
 
27
- export * from './when-dom-loaded';
28
- export * from './when-loaded';
29
- }
26
+ export * from './when-dom-loaded.js';
27
+ export {whenLoaded, scheduleWhenLoaded} from './when-loaded.js';
package/src/index.js ADDED
@@ -0,0 +1,29 @@
1
+ // @ts-self-types="./index.d.ts"
2
+
3
+ export * from './audit.js';
4
+ export * from './batch.js';
5
+ export * from './debounce.js';
6
+ export * from './defer.js';
7
+ export * from './sample.js';
8
+ export * from './sleep.js';
9
+ export * from './throttle.js';
10
+
11
+ export * from './CancelTaskError.js';
12
+ export * from './MicroTask.js';
13
+ export * from './MicroTaskQueue.js';
14
+ export * from './LimitedQueue.js';
15
+ export * from './ListQueue.js';
16
+ export * from './FrameQueue.js';
17
+ export {IdleQueue, idleQueue} from './IdleQueue.js';
18
+
19
+ export * from './Counter.js';
20
+ export * from './PageWatcher.js';
21
+ export * from './Retainer.js';
22
+ export {Task as SchedulerTask, Scheduler, repeat, scheduler} from './Scheduler.js';
23
+ export * from './Throttler.js';
24
+
25
+ export * from './random-dist.js';
26
+ export * from './random-sleep.js';
27
+
28
+ export * from './when-dom-loaded.js';
29
+ export {whenLoaded, scheduleWhenLoaded} from './when-loaded.js';
@@ -13,7 +13,7 @@ export declare function uniform(min: number, max: number): number;
13
13
  * @param skewness The skewness of the distribution.
14
14
  * @returns A random number from the normal distribution.
15
15
  */
16
- export declare function normal(mean: number, stdDev: number, skewness: number = 0): number;
16
+ export declare function normal(mean: number, stdDev: number, skewness?: number): number;
17
17
 
18
18
  /**
19
19
  * Generate a random number from an exponential distribution.
@@ -10,12 +10,15 @@ export const normal = (mean, stdDev, skewness = 0) => {
10
10
  v = 0;
11
11
  while (!u) u = Math.random(); // Converting [0,1) to (0,1)
12
12
  while (!v) v = Math.random();
13
- let z = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v);
14
- if (!skewness) return z * stdDev + mean;
15
- const delta = skewness / Math.sqrt(1 + skewness * skewness),
16
- x = delta * z + Math.sqrt(1 - delta * delta) * v;
17
- z = z >= 0 ? x : -x;
18
- return z * stdDev + mean;
13
+ const r = Math.sqrt(-2.0 * Math.log(u)),
14
+ theta = 2.0 * Math.PI * v,
15
+ z1 = r * Math.cos(theta);
16
+ if (!skewness) return z1 * stdDev + mean;
17
+ // Box-Muller yields two independent N(0,1) samples per (u, v) pair; use both for skew-normal.
18
+ const z2 = r * Math.sin(theta),
19
+ delta = skewness / Math.sqrt(1 + skewness * skewness),
20
+ x = delta * z1 + Math.sqrt(1 - delta * delta) * z2;
21
+ return (z1 >= 0 ? x : -x) * stdDev + mean;
19
22
  };
20
23
 
21
24
  export const expo = lambda => {
@@ -21,7 +21,7 @@ export declare function randomUniformSleep(min: number, max: number): RandomSlee
21
21
  export declare function randomNormalSleep(
22
22
  mean: number,
23
23
  stdDev: number,
24
- skewness: number = 0
24
+ skewness?: number
25
25
  ): RandomSleepFunction;
26
26
 
27
27
  /**
@@ -34,7 +34,7 @@ export declare function randomNormalSleep(
34
34
  export declare function randomExpoSleep(
35
35
  rate: number,
36
36
  range: number,
37
- base: number = 0
37
+ base?: number
38
38
  ): RandomSleepFunction;
39
39
 
40
40
  /**
@@ -44,7 +44,7 @@ export declare function randomExpoSleep(
44
44
  * @returns A sleep function.
45
45
  * @throws Error if the ratio is not between 0.5 and 1.
46
46
  */
47
- export declare function randomParetoSleep(min: number, ratio: number = 0.8): RandomSleepFunction;
47
+ export declare function randomParetoSleep(min: number, ratio?: number): RandomSleepFunction;
48
48
 
49
49
  /**
50
50
  * A simple sleep function that uses a uniform distribution.
@@ -52,6 +52,6 @@ export declare function randomParetoSleep(min: number, ratio: number = 0.8): Ran
52
52
  * @param min The minimum delay in milliseconds.
53
53
  * @returns A promise that resolves after the delay.
54
54
  */
55
- export declare function randomSleep(max: number, min: number = 0): Promise<void>;
55
+ export declare function randomSleep(max: number, min?: number): Promise<void>;
56
56
 
57
57
  export default randomSleep;
package/src/sample.js CHANGED
@@ -6,7 +6,7 @@ export const sample = (fn, ms) => {
6
6
  lastSeenArgs = null,
7
7
  timeout = ms;
8
8
  return (...args) => {
9
- lastSeenArgs = [...args];
9
+ lastSeenArgs = args;
10
10
  if (handle) return;
11
11
  const diff = (Date.now() - started) % ms,
12
12
  delay = diff ? ms - diff : timeout;
@@ -2,10 +2,11 @@
2
2
 
3
3
  import ValueList from 'list-toolkit/value-list.js';
4
4
 
5
+ /** @type {ValueList<() => void>} */
5
6
  const waitingForDom = new ValueList();
6
7
 
7
8
  export const remove = fn => {
8
- for (const node of waitingForDom.getNodeIterable()) {
9
+ for (const node of waitingForDom.getNodeIterator()) {
9
10
  if (node.value === fn) {
10
11
  waitingForDom.removeNode(node);
11
12
  return true;
@@ -2,10 +2,11 @@
2
2
 
3
3
  import ValueList from 'list-toolkit/value-list.js';
4
4
 
5
+ /** @type {ValueList<() => void>} */
5
6
  const waitingForLoad = new ValueList();
6
7
 
7
8
  export const remove = fn => {
8
- for (const node of waitingForLoad.getNodeIterable()) {
9
+ for (const node of waitingForLoad.getNodeIterator()) {
9
10
  if (node.value === fn) {
10
11
  waitingForLoad.removeNode(node);
11
12
  return true;