@hardlydifficult/poller 1.0.17 → 1.0.18
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 +112 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/poller
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
A generic polling utility with debounced triggers, overlapping request handling, and deep equality change detection.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -29,41 +29,130 @@ poller.trigger();
|
|
|
29
29
|
poller.stop();
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
##
|
|
32
|
+
## Poller Creation
|
|
33
|
+
|
|
34
|
+
The `Poller` class supports two constructor styles: a modern options-based approach and a deprecated positional constructor for backward compatibility.
|
|
35
|
+
|
|
36
|
+
### Options-based constructor (recommended)
|
|
33
37
|
|
|
34
38
|
```typescript
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
import { Poller } from "@hardlydifficult/poller";
|
|
40
|
+
|
|
41
|
+
const poller = Poller.create({
|
|
42
|
+
fetch: async () => fetch("/api/data").then(r => r.json()),
|
|
43
|
+
onChange: (current, previous) => console.log("Changed:", current),
|
|
44
|
+
intervalMs: 3000,
|
|
45
|
+
debounceMs: 1000, // optional, defaults to 1000
|
|
46
|
+
onError: (error) => console.error("Poll error:", error), // optional
|
|
47
|
+
comparator: (curr, prev) => curr.id === prev?.id, // optional
|
|
48
|
+
});
|
|
43
49
|
```
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
| Option | Type | Description |
|
|
52
|
+
|--------|------|-------------|
|
|
53
|
+
| `fetch` | `() => Promise<T>` | Async function to fetch data |
|
|
54
|
+
| `onChange` | `(current: T, previous: T \| undefined) => void` | Callback when data changes |
|
|
55
|
+
| `intervalMs` | `number` | Polling interval in milliseconds |
|
|
56
|
+
| `debounceMs` | `number` | Debounce delay for manual triggers (default: `1000`) |
|
|
57
|
+
| `onError` | `(error: unknown) => void` | Error handler (optional) |
|
|
58
|
+
| `comparator` | `(current: T, previous: T \| undefined) => boolean` | Custom change detection (default: deep equality) |
|
|
46
59
|
|
|
47
|
-
|
|
60
|
+
### Deprecated positional constructor
|
|
48
61
|
|
|
49
62
|
```typescript
|
|
50
|
-
const poller = new Poller(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
63
|
+
const poller = new Poller(
|
|
64
|
+
async () => fetch("/api/data").then(r => r.json()),
|
|
65
|
+
(current, previous) => console.log("Changed:", current),
|
|
66
|
+
3000,
|
|
67
|
+
(error) => console.error("Poll error:", error)
|
|
68
|
+
);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
> Note: This style is deprecated; use `Poller.create(options)` or `new Poller(options)` instead.
|
|
72
|
+
|
|
73
|
+
## Polling Control
|
|
74
|
+
|
|
75
|
+
### `start()`
|
|
76
|
+
Starts polling at the configured interval. Returns immediately after the first fetch completes.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
await poller.start();
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### `stop()`
|
|
83
|
+
Stops all timers and prevents further polling.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
poller.stop();
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `trigger(debounceMs?)`
|
|
90
|
+
Manually triggers a poll, debouncing multiple calls.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
poller.trigger(); // Uses default debounceMs
|
|
94
|
+
poller.trigger(2000); // Override debounce delay
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Change Detection
|
|
98
|
+
|
|
99
|
+
By default, the `Poller` uses deep equality to detect changes, supporting primitives, arrays, and plain objects—even when new references are returned.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const poller = Poller.create({
|
|
103
|
+
fetch: async () => ({ count: 42 }),
|
|
104
|
+
onChange: (data, prev) => console.log("Changed:", data),
|
|
55
105
|
intervalMs: 2000,
|
|
56
|
-
onError: (error) => console.error("Poll failed:", error),
|
|
57
106
|
});
|
|
107
|
+
|
|
108
|
+
// Even if fetch returns a new object with same content, onChange won't fire
|
|
58
109
|
```
|
|
59
110
|
|
|
60
|
-
|
|
111
|
+
### Custom comparator
|
|
112
|
+
|
|
113
|
+
You can supply a custom comparator to control change detection logic:
|
|
61
114
|
|
|
62
115
|
```typescript
|
|
63
|
-
const poller =
|
|
64
|
-
fetch: async () => ({ id:
|
|
65
|
-
onChange: (
|
|
116
|
+
const poller = Poller.create({
|
|
117
|
+
fetch: async () => ({ id: 1, name: "Alice" }),
|
|
118
|
+
onChange: (data, prev) => console.log("Changed:", data.name),
|
|
119
|
+
intervalMs: 2000,
|
|
120
|
+
comparator: (current, previous) => current.name === previous?.name,
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Error Handling
|
|
125
|
+
|
|
126
|
+
Errors during fetch or comparator execution are routed to the `onError` callback, if provided. Polling continues after errors.
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const poller = Poller.create({
|
|
130
|
+
fetch: async () => { throw new Error("Network issue"); },
|
|
131
|
+
onChange: () => {},
|
|
66
132
|
intervalMs: 1000,
|
|
67
|
-
|
|
133
|
+
onError: (err) => console.warn("Caught error:", err),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await poller.start(); // Continues polling despite error
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Overlapping Request Handling
|
|
140
|
+
|
|
141
|
+
If a fetch is still pending when the next interval arrives, the new poll is skipped to avoid overlapping requests.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const poller = Poller.create({
|
|
145
|
+
fetch: async () => {
|
|
146
|
+
await new Promise(r => setTimeout(r, 2000)); // Simulate slow fetch
|
|
147
|
+
return "data";
|
|
148
|
+
},
|
|
149
|
+
onChange: () => {},
|
|
150
|
+
intervalMs: 1000, // Won't trigger overlapping fetch
|
|
68
151
|
});
|
|
69
152
|
```
|
|
153
|
+
|
|
154
|
+
## API Reference
|
|
155
|
+
|
|
156
|
+
- `Poller<T>`: Generic polling class
|
|
157
|
+
- `PollerOptions<T>`: Options interface for configuring the poller
|
|
158
|
+
- `Poller.create<T>(options: PollerOptions<T>): Poller<T>`: Static factory method (recommended)
|