@hardlydifficult/poller 1.0.9 → 1.0.11

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 +84 -43
  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
+ A lightweight polling utility with debounced manual triggers, overlapping request handling, and deep equality change detection.
4
4
 
5
5
  ## Installation
6
6
 
@@ -13,81 +13,122 @@ npm install @hardlydifficult/poller
13
13
  ```typescript
14
14
  import { Poller } from "@hardlydifficult/poller";
15
15
 
16
- const fetchFn = async () => {
17
- const response = await fetch("https://api.example.com/data");
18
- return response.json();
19
- };
20
-
21
- const onChange = (current: unknown, previous: unknown) => {
22
- console.log("Data changed:", current);
16
+ const fetchUser = async () => {
17
+ const res = await fetch("https://api.example.com/user");
18
+ return res.json();
23
19
  };
24
20
 
25
- const poller = new Poller(fetchFn, onChange, 5000);
21
+ const poller = new Poller(
22
+ fetchUser,
23
+ (user, previousUser) => {
24
+ console.log("User changed:", user);
25
+ },
26
+ 5000 // Poll every 5 seconds
27
+ );
26
28
 
27
29
  await poller.start();
28
- // => Starts polling every 5 seconds, firing onChange on first fetch and any change
30
+ // Polling begins immediately and every 5 seconds
29
31
 
30
- poller.trigger(1000);
31
- // => Triggers a debounced poll after 1 second (overriding any previous trigger call)
32
- ```
32
+ // Optionally, manually trigger a poll with debounce
33
+ poller.trigger(1000); // Fires after 1s of inactivity
33
34
 
34
- ## Poller Class
35
+ // Stop polling when no longer needed
36
+ poller.stop();
37
+ ```
35
38
 
36
- A generic polling utility that periodically fetches data and invokes a callback when the result changes.
39
+ ## Polling with Change Detection
37
40
 
38
- ### Constructor
41
+ The `Poller` class periodically fetches data using a user-provided async function and invokes a callback only when the result changes. Change detection uses deep equality via `JSON.stringify`, ensuring structurally identical values (even with different object references) do not trigger redundant callbacks.
39
42
 
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 |
43
+ ### Constructor Parameters
46
44
 
47
- ### Methods
45
+ | Parameter | Type | Description |
46
+ |------|--|---------|
47
+ | `fetchFn` | `() => Promise<T>` | Async function that fetches the data to poll |
48
+ | `onChange` | `(current: T, previous: T \| undefined) => void` | Callback invoked when data changes (using deep equality) |
49
+ | `intervalMs` | `number` | Polling interval in milliseconds |
50
+ | `onError?` | `(error: unknown) => void` | Optional callback for fetch errors |
48
51
 
49
- #### `start(): Promise<void>`
52
+ ### `start(): Promise<void>`
50
53
 
51
- Starts polling at the configured interval. Does nothing if already running.
54
+ Begins polling immediately and at the configured interval.
52
55
 
53
56
  ```typescript
54
57
  await poller.start();
55
- // => Begins polling; invokes onChange immediately on first fetch
58
+ // Polls once immediately, then every intervalMs ms
56
59
  ```
57
60
 
58
- #### `stop(): void`
61
+ ### `stop(): void`
59
62
 
60
- Stops polling and clears all timers (including any pending debounced trigger).
63
+ Stops polling and clears any pending debounced triggers.
61
64
 
62
65
  ```typescript
63
66
  poller.stop();
64
- // => Immediately halts polling and cancels pending triggers
67
+ // No further polls occur; timers cleared
65
68
  ```
66
69
 
67
- #### `trigger(debounceMs = 1000): void`
70
+ ### `trigger(debounceMs?: number): void`
68
71
 
69
- Triggers a debounced poll. Multiple rapid calls reset the debounce timer.
72
+ Manually trigger a poll with debouncing to avoid excessive requests during rapid events.
70
73
 
71
74
  ```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
75
+ // Default debounce: 1000ms
76
+ poller.trigger();
77
+
78
+ // Custom debounce
79
+ poller.trigger(2000); // Fires after 2 seconds of no other triggers
75
80
  ```
76
81
 
77
- ### Behavior
82
+ ## Debounced Manual Trigger
78
83
 
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.
84
+ The `trigger()` method allows manually forcing a poll while debouncing multiple rapid calls:
85
+
86
+ ```typescript
87
+ await poller.start();
88
+ poller.trigger(500); // Schedules a poll after 500ms
89
+ poller.trigger(500); // Resets debounce — only one poll fires
90
+ ```
91
+
92
+ ## Error Handling
93
+
94
+ Errors during polling do not halt the poller. They are optionally reported via `onError`, if provided.
82
95
 
83
96
  ```typescript
84
97
  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)
98
+ async () => {
99
+ throw new Error("Network failure");
100
+ },
101
+ (data) => console.log(data),
102
+ 2000,
103
+ (error) => console.error("Poll failed:", error)
89
104
  );
105
+ await poller.start();
106
+ // Logs: Poll failed: Error: Network failure
107
+ // Continues polling after each error
108
+ ```
109
+
110
+ ## Overlapping Request Handling
90
111
 
112
+ The `Poller` skips new polls while a fetch is still in progress, preventing overlapping requests.
113
+
114
+ ```typescript
115
+ const fetchFn = async () => {
116
+ // Simulates slow network — never resolves before interval
117
+ await new Promise((resolve) => setTimeout(resolve, 6000));
118
+ return "data";
119
+ };
120
+ const poller = new Poller(fetchFn, () => {}, 1000);
91
121
  await poller.start();
92
- poller.trigger(500); // Manual override after 0.5s if triggered again
122
+ // Only one fetch runs at a time — subsequent intervals are skipped until it completes
123
+ ```
124
+
125
+ ## Deep Equality Detection
126
+
127
+ The `Poller` uses `JSON.stringify` to compare current and previous values, enabling detection of structural changes in objects and arrays.
128
+
129
+ ```typescript
130
+ const fetchCount = async () => ({ value: 1 });
131
+ const poller = new Poller(fetchCount, (curr, prev) => {
132
+ // Fires only when value changes
133
+ }, 1000);
93
134
  ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hardlydifficult/poller",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "main": "./dist/index.js",
5
5
  "types": "./dist/index.d.ts",
6
6
  "files": [