@hardlydifficult/poller 1.0.3 → 1.0.5
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 +77 -47
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @hardlydifficult/poller
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A generic polling utility that periodically fetches data and invokes a callback only when the result changes, using JSON-based deep equality comparison.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npm install @hardlydifficult/poller
|
|
@@ -13,6 +13,31 @@ 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
|
+
const poller = new Poller(
|
|
18
|
+
async () => {
|
|
19
|
+
const response = await fetch("https://api.example.com/status");
|
|
20
|
+
return await response.json();
|
|
21
|
+
},
|
|
22
|
+
(current, previous) => {
|
|
23
|
+
console.log("Status changed:", current);
|
|
24
|
+
},
|
|
25
|
+
5000,
|
|
26
|
+
(error) => {
|
|
27
|
+
console.error("Polling error:", error);
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
await poller.start(); // Begins polling immediately
|
|
32
|
+
// ... later
|
|
33
|
+
poller.stop(); // Stops polling
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Basic Usage
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { Poller } from "@hardlydifficult/poller";
|
|
40
|
+
|
|
16
41
|
const poller = new Poller(
|
|
17
42
|
async () => await fetchCurrentState(),
|
|
18
43
|
(current, previous) => console.log("State changed!", current),
|
|
@@ -30,7 +55,7 @@ poller.stop();
|
|
|
30
55
|
|
|
31
56
|
## Polling
|
|
32
57
|
|
|
33
|
-
The `Poller` class
|
|
58
|
+
The `Poller` class fetches data at a configurable interval and invokes a callback when the result changes. It fetches immediately on `start()`, then at the configured interval.
|
|
34
59
|
|
|
35
60
|
```typescript
|
|
36
61
|
import { Poller } from "@hardlydifficult/poller";
|
|
@@ -51,9 +76,30 @@ await poller.start();
|
|
|
51
76
|
// Fetches immediately, then every 10 seconds
|
|
52
77
|
```
|
|
53
78
|
|
|
79
|
+
### `start()`
|
|
80
|
+
|
|
81
|
+
Starts polling. Fetches immediately, then at the configured interval. Calling `start()` multiple times is safe (idempotent).
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
await poller.start(); // Fetches immediately
|
|
85
|
+
await poller.start(); // No-op, already running
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### `stop()`
|
|
89
|
+
|
|
90
|
+
Stops polling and cleans up all timers.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
poller.stop();
|
|
94
|
+
// No more polls will fire
|
|
95
|
+
```
|
|
96
|
+
|
|
54
97
|
## Change Detection
|
|
55
98
|
|
|
56
|
-
Changes are detected using JSON serialization for deep equality. Structurally identical objects are considered unchanged
|
|
99
|
+
Changes are detected using JSON serialization for deep equality. Structurally identical objects are considered unchanged—even if they are different references.
|
|
100
|
+
|
|
101
|
+
- On first poll, `onChange(current, undefined)` is invoked.
|
|
102
|
+
- On subsequent polls, `onChange(current, previous)` is invoked only if the new value differs structurally.
|
|
57
103
|
|
|
58
104
|
```typescript
|
|
59
105
|
const poller = new Poller(
|
|
@@ -72,6 +118,10 @@ await poller.start();
|
|
|
72
118
|
|
|
73
119
|
Call `trigger()` to manually poll immediately, with optional debouncing. Multiple rapid triggers are coalesced into a single poll.
|
|
74
120
|
|
|
121
|
+
- Accepts a `debounceMs` parameter (default: `1000`).
|
|
122
|
+
- Multiple rapid calls reset the debounce timer — only the last trigger fires.
|
|
123
|
+
- No-op if the poller is not running.
|
|
124
|
+
|
|
75
125
|
```typescript
|
|
76
126
|
const poller = new Poller(
|
|
77
127
|
async () => await fetchData(),
|
|
@@ -95,7 +145,8 @@ poller.trigger(500); // Only one poll fires after 500ms
|
|
|
95
145
|
|
|
96
146
|
## Error Handling
|
|
97
147
|
|
|
98
|
-
Errors during fetch are passed to the optional `onError` callback.
|
|
148
|
+
- Errors during fetch are caught and passed to the optional `onError` callback.
|
|
149
|
+
- Polling continues after errors — no automatic retry logic is applied.
|
|
99
150
|
|
|
100
151
|
```typescript
|
|
101
152
|
const poller = new Poller(
|
|
@@ -111,63 +162,42 @@ const poller = new Poller(
|
|
|
111
162
|
await poller.start();
|
|
112
163
|
```
|
|
113
164
|
|
|
114
|
-
##
|
|
165
|
+
## Core Features
|
|
115
166
|
|
|
116
|
-
###
|
|
117
|
-
|
|
118
|
-
Starts polling. Fetches immediately, then at the configured interval. Calling `start()` multiple times is safe (idempotent).
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
const poller = new Poller(
|
|
122
|
-
async () => await fetchData(),
|
|
123
|
-
(current) => console.log("Updated:", current),
|
|
124
|
-
5000
|
|
125
|
-
);
|
|
167
|
+
### Polling Lifecycle
|
|
126
168
|
|
|
127
|
-
|
|
128
|
-
await poller.start(); // No-op, already running
|
|
129
|
-
```
|
|
169
|
+
The `Poller` manages its lifecycle with `start()` and `stop()` methods.
|
|
130
170
|
|
|
131
|
-
|
|
171
|
+
- `start()`: Begins polling immediately and then at the configured interval. Idempotent — calling it multiple times has no effect after the first call.
|
|
172
|
+
- `stop()`: Clears the polling timer and any pending debounced triggers. No-op if already stopped.
|
|
132
173
|
|
|
133
|
-
|
|
174
|
+
### Concurrent Fetch Handling
|
|
134
175
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// No more polls will fire
|
|
138
|
-
```
|
|
176
|
+
Overlapping fetches (e.g., due to slow network) are automatically skipped:
|
|
177
|
+
- If `poll()` is already running when the interval fires, the next poll is skipped until the current one completes.
|
|
139
178
|
|
|
140
179
|
## API Reference
|
|
141
180
|
|
|
142
|
-
### Constructor
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
new Poller<T>(
|
|
146
|
-
fetchFn: () => Promise<T>,
|
|
147
|
-
onChange: (current: T, previous: T | undefined) => void,
|
|
148
|
-
intervalMs: number,
|
|
149
|
-
onError?: (error: unknown) => void
|
|
150
|
-
)
|
|
151
|
-
```
|
|
181
|
+
### `Poller<T>` Constructor
|
|
152
182
|
|
|
153
|
-
| Parameter | Description
|
|
154
|
-
|
|
155
|
-
| `fetchFn` | Async function
|
|
156
|
-
| `onChange`
|
|
157
|
-
| `intervalMs`
|
|
158
|
-
| `onError` | Optional
|
|
183
|
+
| Parameter | Type | Description |
|
|
184
|
+
|-------------|---------------------------------------|------------------------------------------|
|
|
185
|
+
| `fetchFn` | `() => Promise<T>` | Async function returning the current state |
|
|
186
|
+
| `onChange` | `(current: T, previous: T | undefined) => void` | Callback invoked on state changes |
|
|
187
|
+
| `intervalMs`| `number` | Polling interval in milliseconds |
|
|
188
|
+
| `onError?` | `(error: unknown) => void` | Optional callback for fetch errors |
|
|
159
189
|
|
|
160
190
|
### Methods
|
|
161
191
|
|
|
162
|
-
| Method | Description
|
|
163
|
-
|
|
164
|
-
| `start()` |
|
|
165
|
-
| `stop()` |
|
|
166
|
-
| `trigger(
|
|
192
|
+
| Method | Signature | Description |
|
|
193
|
+
|--------------|----------------------------------------|----------------------------------------------|
|
|
194
|
+
| `start()` | `(): Promise<void>` | Begins polling (immediate + interval-based) |
|
|
195
|
+
| `stop()` | `(): void` | Stops polling and clears timers |
|
|
196
|
+
| `trigger()` | `(debounceMs?: number) => void` | Triggers a debounced manual poll |
|
|
167
197
|
|
|
168
198
|
### Behavior
|
|
169
199
|
|
|
170
|
-
- **Deep equality** — uses JSON serialization to detect changes
|
|
200
|
+
- **Deep equality** — uses JSON serialization to detect structural changes
|
|
171
201
|
- **Overlap prevention** — skips a poll if the previous fetch is still running
|
|
172
202
|
- **Error resilience** — continues polling after fetch errors
|
|
173
203
|
- **Idempotent start** — calling `start()` multiple times is safe
|