@hardlydifficult/poller 1.0.2 → 1.0.4
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 +124 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/poller
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Polls async functions at configurable intervals and triggers callbacks only when the result changes—using deep equality detection via JSON serialization.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ Generic state-change poller. Polls a function at an interval and fires a callbac
|
|
|
8
8
|
npm install @hardlydifficult/poller
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { Poller } from "@hardlydifficult/poller";
|
|
@@ -28,26 +28,139 @@ poller.trigger(1000);
|
|
|
28
28
|
poller.stop();
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## Polling
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
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
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { Poller } from "@hardlydifficult/poller";
|
|
37
|
+
|
|
38
|
+
const poller = new Poller(
|
|
39
|
+
async () => {
|
|
40
|
+
const response = await fetch("/api/status");
|
|
41
|
+
return response.json();
|
|
42
|
+
},
|
|
43
|
+
(current, previous) => {
|
|
44
|
+
console.log("Previous:", previous);
|
|
45
|
+
console.log("Current:", current);
|
|
46
|
+
},
|
|
47
|
+
10000 // poll every 10 seconds
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
await poller.start();
|
|
51
|
+
// Fetches immediately, then every 10 seconds
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### start()
|
|
55
|
+
|
|
56
|
+
Starts polling. Fetches immediately, then at the configured interval. Calling `start()` multiple times is safe (idempotent).
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
await poller.start(); // Fetches immediately
|
|
60
|
+
await poller.start(); // No-op, already running
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### stop()
|
|
64
|
+
|
|
65
|
+
Stops polling and cleans up all timers.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
poller.stop();
|
|
69
|
+
// No more polls will fire
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Change Detection
|
|
73
|
+
|
|
74
|
+
Changes are detected using JSON serialization for deep equality. Structurally identical objects are considered unchanged—even if they are different references.
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const poller = new Poller(
|
|
78
|
+
async () => ({ count: 5, items: [1, 2, 3] }),
|
|
79
|
+
(current, previous) => {
|
|
80
|
+
// Only fires when the JSON representation changes
|
|
81
|
+
console.log("Changed from", previous, "to", current);
|
|
82
|
+
},
|
|
83
|
+
5000
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
await poller.start();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Manual Triggers
|
|
90
|
+
|
|
91
|
+
Call `trigger()` to manually poll immediately, with optional debouncing. Multiple rapid triggers are coalesced into a single poll.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
const poller = new Poller(
|
|
95
|
+
async () => await fetchData(),
|
|
96
|
+
(current, previous) => console.log("Updated:", current),
|
|
97
|
+
60000
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
await poller.start();
|
|
101
|
+
|
|
102
|
+
// Trigger a poll with 1000ms debounce (default)
|
|
103
|
+
poller.trigger();
|
|
104
|
+
|
|
105
|
+
// Trigger with custom debounce
|
|
106
|
+
poller.trigger(500);
|
|
107
|
+
|
|
108
|
+
// Multiple rapid triggers coalesce into one poll
|
|
109
|
+
poller.trigger(500);
|
|
110
|
+
poller.trigger(500);
|
|
111
|
+
poller.trigger(500); // Only one poll fires after 500ms
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Error Handling
|
|
115
|
+
|
|
116
|
+
Errors during fetch are passed to the optional `onError` callback. Polling continues regardless of errors.
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const poller = new Poller(
|
|
120
|
+
async () => await fetchData(),
|
|
121
|
+
(current, previous) => console.log("Updated:", current),
|
|
122
|
+
5000,
|
|
123
|
+
(error) => {
|
|
124
|
+
console.error("Fetch failed:", error);
|
|
125
|
+
// Polling continues automatically
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
await poller.start();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## API Reference
|
|
133
|
+
|
|
134
|
+
### Constructor
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
new Poller<T>(
|
|
138
|
+
fetchFn: () => Promise<T>,
|
|
139
|
+
onChange: (current: T, previous: T | undefined) => void,
|
|
140
|
+
intervalMs: number,
|
|
141
|
+
onError?: (error: unknown) => void
|
|
142
|
+
)
|
|
143
|
+
```
|
|
34
144
|
|
|
35
145
|
| Parameter | Description |
|
|
36
|
-
|
|
146
|
+
|---|---|
|
|
37
147
|
| `fetchFn` | Async function that returns the current state |
|
|
38
148
|
| `onChange` | Called with `(current, previous)` when state changes |
|
|
39
149
|
| `intervalMs` | Polling interval in milliseconds |
|
|
40
150
|
| `onError` | Optional error handler; polling continues on errors |
|
|
41
151
|
|
|
152
|
+
### Methods
|
|
153
|
+
|
|
42
154
|
| Method | Description |
|
|
43
|
-
|
|
155
|
+
|---|---|
|
|
44
156
|
| `start()` | Start polling (fetches immediately, then at interval) |
|
|
45
157
|
| `stop()` | Stop polling and clean up timers |
|
|
46
|
-
| `trigger(debounceMs?)` | Manually trigger a poll with debounce (default
|
|
158
|
+
| `trigger(debounceMs?)` | Manually trigger a poll with debounce (default `1000`ms) |
|
|
47
159
|
|
|
48
160
|
### Behavior
|
|
49
161
|
|
|
50
|
-
- **Deep equality**
|
|
51
|
-
- **Overlap prevention**
|
|
52
|
-
- **Error resilience**
|
|
53
|
-
- **Idempotent start**
|
|
162
|
+
- **Deep equality** — uses JSON serialization to detect structural changes
|
|
163
|
+
- **Overlap prevention** — skips a poll if the previous fetch is still running
|
|
164
|
+
- **Error resilience** — continues polling after fetch errors
|
|
165
|
+
- **Idempotent start** — calling `start()` multiple times is safe
|
|
166
|
+
- **Debounced triggers** — multiple `trigger()` calls coalesce into one poll
|