@hardlydifficult/poller 1.0.5 → 1.0.7
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/README.md +92 -38
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/poller
|
|
2
2
|
|
|
3
|
-
A generic polling utility that periodically fetches data
|
|
3
|
+
A generic polling utility that periodically fetches data, detects changes via deep equality comparison, and supports debounced manual triggers with overlap handling.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -13,24 +13,25 @@ npm install @hardlydifficult/poller
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { Poller } from "@hardlydifficult/poller";
|
|
15
15
|
|
|
16
|
-
// Create a poller that fetches mock API data every 5 seconds
|
|
17
16
|
const poller = new Poller(
|
|
18
17
|
async () => {
|
|
19
|
-
const
|
|
20
|
-
return
|
|
18
|
+
const res = await fetch("https://api.example.com/status");
|
|
19
|
+
return res.json();
|
|
21
20
|
},
|
|
22
21
|
(current, previous) => {
|
|
23
22
|
console.log("Status changed:", current);
|
|
24
23
|
},
|
|
25
|
-
5000
|
|
26
|
-
(error) => {
|
|
27
|
-
console.error("Polling error:", error);
|
|
28
|
-
}
|
|
24
|
+
5000 // poll every 5 seconds
|
|
29
25
|
);
|
|
30
26
|
|
|
31
|
-
await poller.start();
|
|
32
|
-
//
|
|
33
|
-
|
|
27
|
+
await poller.start();
|
|
28
|
+
// Polls start immediately
|
|
29
|
+
|
|
30
|
+
// Optionally, manually trigger a debounced poll
|
|
31
|
+
poller.trigger(1000); // fires once after 1s of inactivity
|
|
32
|
+
|
|
33
|
+
// Stop polling when done
|
|
34
|
+
poller.stop();
|
|
34
35
|
```
|
|
35
36
|
|
|
36
37
|
### Basic Usage
|
|
@@ -53,27 +54,62 @@ poller.trigger(1000);
|
|
|
53
54
|
poller.stop();
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
## Polling
|
|
57
|
+
## Polling Behavior
|
|
57
58
|
|
|
58
|
-
The `Poller`
|
|
59
|
+
The `Poller` executes a fetch function at a fixed interval and invokes a callback only when the returned value changes.
|
|
60
|
+
|
|
61
|
+
- Starts polling immediately on `start()`
|
|
62
|
+
- Fetches at the configured `intervalMs`
|
|
63
|
+
- Skips overlapping fetches (if a previous fetch is still in progress)
|
|
59
64
|
|
|
60
65
|
```typescript
|
|
61
|
-
|
|
66
|
+
const poller = new Poller(
|
|
67
|
+
async () => fetchJson("/api/data"),
|
|
68
|
+
(current, previous) => console.log("Changed:", current),
|
|
69
|
+
10_000
|
|
70
|
+
);
|
|
71
|
+
await poller.start();
|
|
72
|
+
```
|
|
62
73
|
|
|
74
|
+
## Change Detection
|
|
75
|
+
|
|
76
|
+
Changes are detected using deep equality via `JSON.stringify`. Structural equality means that objects with identical content—even different references—won’t trigger unnecessary callbacks.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
63
79
|
const poller = new Poller(
|
|
64
|
-
async () => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
80
|
+
async () => ({ items: [1, 2, 3] }),
|
|
81
|
+
(current, previous) => console.log("Changed:", current),
|
|
82
|
+
1000
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Even if a new object instance is returned, same structure = no change
|
|
86
|
+
await poller.start();
|
|
87
|
+
// onChange fires only when structure changes
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- On first poll, `onChange(current, undefined)` is invoked.
|
|
91
|
+
- On subsequent polls, `onChange(current, previous)` is invoked only if the new value differs structurally.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const poller = new Poller(
|
|
95
|
+
async () => ({ count: 5, items: [1, 2, 3] }),
|
|
68
96
|
(current, previous) => {
|
|
69
|
-
|
|
70
|
-
console.log("
|
|
97
|
+
// Only fires when the JSON representation changes
|
|
98
|
+
console.log("Changed from", previous, "to", current);
|
|
71
99
|
},
|
|
72
|
-
|
|
100
|
+
5000
|
|
73
101
|
);
|
|
74
102
|
|
|
75
103
|
await poller.start();
|
|
76
|
-
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Lifecycle Management
|
|
107
|
+
|
|
108
|
+
Polling can be started and stopped at any time. The `stop()` method cancels both the periodic timer and any pending debounced triggers.
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
await poller.start(); // begins polling
|
|
112
|
+
poller.stop(); // cancels all timers, stops future polls
|
|
77
113
|
```
|
|
78
114
|
|
|
79
115
|
### `start()`
|
|
@@ -94,29 +130,28 @@ poller.stop();
|
|
|
94
130
|
// No more polls will fire
|
|
95
131
|
```
|
|
96
132
|
|
|
97
|
-
##
|
|
133
|
+
## Manual Triggers
|
|
98
134
|
|
|
99
|
-
|
|
135
|
+
You can manually trigger a debounced poll to force an immediate check after a period of inactivity.
|
|
100
136
|
|
|
101
|
-
|
|
102
|
-
|
|
137
|
+
| Parameter | Type | Default | Description |
|
|
138
|
+
|-------------|----------|---------|----------------------------------------|
|
|
139
|
+
| `debounceMs`| `number` | `1000` | Milliseconds to wait before polling |
|
|
103
140
|
|
|
104
141
|
```typescript
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
(current, previous) => {
|
|
108
|
-
// Only fires when the JSON representation changes
|
|
109
|
-
console.log("Changed from", previous, "to", current);
|
|
110
|
-
},
|
|
111
|
-
5000
|
|
112
|
-
);
|
|
142
|
+
// Immediate trigger with default debounce
|
|
143
|
+
poller.trigger();
|
|
113
144
|
|
|
114
|
-
|
|
115
|
-
|
|
145
|
+
// Custom debounce
|
|
146
|
+
poller.trigger(500);
|
|
116
147
|
|
|
117
|
-
|
|
148
|
+
// If multiple triggers occur within debounceMs, only the last one fires
|
|
149
|
+
poller.trigger();
|
|
150
|
+
poller.trigger();
|
|
151
|
+
poller.trigger(); // only this one will poll after 1s
|
|
152
|
+
```
|
|
118
153
|
|
|
119
|
-
|
|
154
|
+
### Behavior
|
|
120
155
|
|
|
121
156
|
- Accepts a `debounceMs` parameter (default: `1000`).
|
|
122
157
|
- Multiple rapid calls reset the debounce timer — only the last trigger fires.
|
|
@@ -145,6 +180,25 @@ poller.trigger(500); // Only one poll fires after 500ms
|
|
|
145
180
|
|
|
146
181
|
## Error Handling
|
|
147
182
|
|
|
183
|
+
Fetch errors do not halt polling. An optional `onError` callback receives any errors, and polling continues at the next interval.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const poller = new Poller(
|
|
187
|
+
async () => {
|
|
188
|
+
if (Math.random() < 0.5) throw new Error("Network fail");
|
|
189
|
+
return "ok";
|
|
190
|
+
},
|
|
191
|
+
(current) => console.log(current),
|
|
192
|
+
1000,
|
|
193
|
+
(error) => console.error("Fetch failed:", error)
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
await poller.start();
|
|
197
|
+
// Continues polling even after errors
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Error Handling Details
|
|
201
|
+
|
|
148
202
|
- Errors during fetch are caught and passed to the optional `onError` callback.
|
|
149
203
|
- Polling continues after errors — no automatic retry logic is applied.
|
|
150
204
|
|