@hardlydifficult/poller 1.0.9 → 1.0.10

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 (2) hide show
  1. package/README.md +53 -46
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @hardlydifficult/poller
2
2
 
3
- A lightweight polling utility with debounced triggers, overlapping request handling, and deep equality change detection.
3
+ Lightweight polling utility with debounced triggers, overlapping request handling, and deep equality change detection.
4
4
 
5
5
  ## Installation
6
6
 
@@ -14,80 +14,87 @@ npm install @hardlydifficult/poller
14
14
  import { Poller } from "@hardlydifficult/poller";
15
15
 
16
16
  const fetchFn = async () => {
17
- const response = await fetch("https://api.example.com/data");
17
+ const response = await fetch("https://api.example.com/status");
18
18
  return response.json();
19
19
  };
20
20
 
21
- const onChange = (current: unknown, previous: unknown) => {
22
- console.log("Data changed:", current);
23
- };
24
-
25
- const poller = new Poller(fetchFn, onChange, 5000);
21
+ const poller = new Poller(
22
+ fetchFn,
23
+ (data, prev) => console.log("Data changed:", data),
24
+ 5000 // 5-second interval
25
+ );
26
26
 
27
27
  await poller.start();
28
- // => Starts polling every 5 seconds, firing onChange on first fetch and any change
28
+ // Polls every 5 seconds and logs only when data changes
29
29
 
30
- poller.trigger(1000);
31
- // => Triggers a debounced poll after 1 second (overriding any previous trigger call)
30
+ // Later, stop polling
31
+ poller.stop();
32
32
  ```
33
33
 
34
- ## Poller Class
34
+ ## Polling with Change Detection
35
35
 
36
- A generic polling utility that periodically fetches data and invokes a callback when the result changes.
36
+ The `Poller` class polls a fetch function periodically and invokes a callback only when the result changes. Change detection uses deep equality via `JSON.stringify` comparison, ensuring that structurally identical values (even with different object references) do not trigger redundant callbacks.
37
37
 
38
- ### Constructor
38
+ ### Constructor Parameters
39
39
 
40
- | Parameter | Type | Description |
41
- |--------------|-----------------------------------|----------------------------------------------|
42
- | `fetchFn` | `() => Promise<T>` | Async function that fetches the latest data |
43
- | `onChange` | `(current: T, previous: T | undefined) => void` | Callback invoked when data changes |
44
- | `intervalMs` | `number` | Polling interval in milliseconds |
45
- | `onError?` | `(error: unknown) => void` | Optional callback invoked on fetch errors |
40
+ | Parameter | Type | Description |
41
+ |-------------|-------------------------------------|-----------------------------------------------------|
42
+ | `fetchFn` | `() => Promise<T>` | Async function that returns the data to poll |
43
+ | `onChange` | `(current: T, previous: T | undefined) => void` | Callback invoked when data changes |
44
+ | `intervalMs`| `number` | Polling interval in milliseconds |
45
+ | `onError?` | `(error: unknown) => void` (optional) | Optional error handler for fetch failures |
46
46
 
47
- ### Methods
48
-
49
- #### `start(): Promise<void>`
50
-
51
- Starts polling at the configured interval. Does nothing if already running.
47
+ ### Poller API
52
48
 
53
49
  ```typescript
50
+ // Start polling (idempotent — safe to call multiple times)
54
51
  await poller.start();
55
- // => Begins polling; invokes onChange immediately on first fetch
56
- ```
57
-
58
- #### `stop(): void`
59
52
 
60
- Stops polling and clears all timers (including any pending debounced trigger).
61
-
62
- ```typescript
53
+ // Stop polling and clear timers
63
54
  poller.stop();
64
- // => Immediately halts polling and cancels pending triggers
55
+
56
+ // Manually trigger a poll (debounced by default)
57
+ poller.trigger(1000); // Debounced 1s (default 1000ms)
65
58
  ```
66
59
 
67
- #### `trigger(debounceMs = 1000): void`
60
+ ### Debounced Manual Trigger
68
61
 
69
- Triggers a debounced poll. Multiple rapid calls reset the debounce timer.
62
+ The `trigger()` method allows manually forcing a poll while debouncing multiple rapid calls:
70
63
 
71
64
  ```typescript
72
- poller.trigger(500); // Debounce: 500 ms
73
- poller.trigger(200); // Resets to 200 ms from now
74
- // Only one poll fires after the last trigger delay
65
+ await poller.start();
66
+ poller.trigger(500); // Schedules a poll after 500ms
67
+ poller.trigger(500); // Resets debounce — only one poll fires
75
68
  ```
76
69
 
77
- ### Behavior
70
+ ### Error Handling
78
71
 
79
- - **Deep equality detection**: Uses `JSON.stringify` to detect structural changes, even with new object references.
80
- - **Overlapping request handling**: Skips polls while a fetch is in progress.
81
- - **Error resilience**: Continues polling on errors if `onError` is provided; otherwise, errors are silently ignored.
72
+ Errors during polling do not halt the poller. They are optionally reported via `onError`, if provided.
82
73
 
83
74
  ```typescript
84
75
  const poller = new Poller(
85
- async () => fetch("https://api.example.com/status").then(r => r.json()),
86
- (current, previous) => console.log("Status changed:", current),
87
- 10000, // 10 seconds
88
- (error) => console.error("Polling error:", error)
76
+ async () => {
77
+ throw new Error("Network failure");
78
+ },
79
+ (data) => console.log(data),
80
+ 2000,
81
+ (error) => console.error("Poll failed:", error)
89
82
  );
83
+ await poller.start();
84
+ // Logs: Poll failed: Error: Network failure
85
+ // Continues polling after each error
86
+ ```
87
+
88
+ ## Overlapping Request Handling
90
89
 
90
+ The `Poller` skips new polls while a fetch is still in progress, preventing overlapping requests.
91
+
92
+ ```typescript
93
+ const fetchFn = vi.fn().mockImplementation(() => {
94
+ // Simulates slow network — never resolves before interval
95
+ return new Promise((resolve) => setTimeout(() => resolve("data"), 6000));
96
+ });
97
+ const poller = new Poller(fetchFn, () => {}, 1000);
91
98
  await poller.start();
92
- poller.trigger(500); // Manual override after 0.5s if triggered again
99
+ // Only one fetch runs at a time — subsequent intervals are skipped until it completes
93
100
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/poller",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [