@hardlydifficult/poller 1.0.9 → 1.0.10
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 +53 -46
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @hardlydifficult/poller
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Lightweight polling utility with debounced triggers, overlapping request handling, and deep equality change detection.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -14,80 +14,87 @@ npm install @hardlydifficult/poller
|
|
|
14
14
|
import { Poller } from "@hardlydifficult/poller";
|
|
15
15
|
|
|
16
16
|
const fetchFn = async () => {
|
|
17
|
-
const response = await fetch("https://api.example.com/
|
|
17
|
+
const response = await fetch("https://api.example.com/status");
|
|
18
18
|
return response.json();
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const poller = new Poller(
|
|
22
|
+
fetchFn,
|
|
23
|
+
(data, prev) => console.log("Data changed:", data),
|
|
24
|
+
5000 // 5-second interval
|
|
25
|
+
);
|
|
26
26
|
|
|
27
27
|
await poller.start();
|
|
28
|
-
//
|
|
28
|
+
// Polls every 5 seconds and logs only when data changes
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
// Later, stop polling
|
|
31
|
+
poller.stop();
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Polling with Change Detection
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
The `Poller` class polls a fetch function periodically and invokes a callback only when the result changes. Change detection uses deep equality via `JSON.stringify` comparison, ensuring that structurally identical values (even with different object references) do not trigger redundant callbacks.
|
|
37
37
|
|
|
38
|
-
### Constructor
|
|
38
|
+
### Constructor Parameters
|
|
39
39
|
|
|
40
|
-
| Parameter
|
|
41
|
-
|
|
42
|
-
| `fetchFn`
|
|
43
|
-
| `onChange`
|
|
44
|
-
| `intervalMs
|
|
45
|
-
| `onError?`
|
|
40
|
+
| Parameter | Type | Description |
|
|
41
|
+
|-------------|-------------------------------------|-----------------------------------------------------|
|
|
42
|
+
| `fetchFn` | `() => Promise<T>` | Async function that returns the data to poll |
|
|
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) | Optional error handler for fetch failures |
|
|
46
46
|
|
|
47
|
-
###
|
|
48
|
-
|
|
49
|
-
#### `start(): Promise<void>`
|
|
50
|
-
|
|
51
|
-
Starts polling at the configured interval. Does nothing if already running.
|
|
47
|
+
### Poller API
|
|
52
48
|
|
|
53
49
|
```typescript
|
|
50
|
+
// Start polling (idempotent — safe to call multiple times)
|
|
54
51
|
await poller.start();
|
|
55
|
-
// => Begins polling; invokes onChange immediately on first fetch
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
#### `stop(): void`
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```typescript
|
|
53
|
+
// Stop polling and clear timers
|
|
63
54
|
poller.stop();
|
|
64
|
-
|
|
55
|
+
|
|
56
|
+
// Manually trigger a poll (debounced by default)
|
|
57
|
+
poller.trigger(1000); // Debounced 1s (default 1000ms)
|
|
65
58
|
```
|
|
66
59
|
|
|
67
|
-
|
|
60
|
+
### Debounced Manual Trigger
|
|
68
61
|
|
|
69
|
-
|
|
62
|
+
The `trigger()` method allows manually forcing a poll while debouncing multiple rapid calls:
|
|
70
63
|
|
|
71
64
|
```typescript
|
|
72
|
-
poller.
|
|
73
|
-
poller.trigger(
|
|
74
|
-
//
|
|
65
|
+
await poller.start();
|
|
66
|
+
poller.trigger(500); // Schedules a poll after 500ms
|
|
67
|
+
poller.trigger(500); // Resets debounce — only one poll fires
|
|
75
68
|
```
|
|
76
69
|
|
|
77
|
-
###
|
|
70
|
+
### Error Handling
|
|
78
71
|
|
|
79
|
-
|
|
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.
|
|
72
|
+
Errors during polling do not halt the poller. They are optionally reported via `onError`, if provided.
|
|
82
73
|
|
|
83
74
|
```typescript
|
|
84
75
|
const poller = new Poller(
|
|
85
|
-
async () =>
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
(
|
|
76
|
+
async () => {
|
|
77
|
+
throw new Error("Network failure");
|
|
78
|
+
},
|
|
79
|
+
(data) => console.log(data),
|
|
80
|
+
2000,
|
|
81
|
+
(error) => console.error("Poll failed:", error)
|
|
89
82
|
);
|
|
83
|
+
await poller.start();
|
|
84
|
+
// Logs: Poll failed: Error: Network failure
|
|
85
|
+
// Continues polling after each error
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Overlapping Request Handling
|
|
90
89
|
|
|
90
|
+
The `Poller` skips new polls while a fetch is still in progress, preventing overlapping requests.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const fetchFn = vi.fn().mockImplementation(() => {
|
|
94
|
+
// Simulates slow network — never resolves before interval
|
|
95
|
+
return new Promise((resolve) => setTimeout(() => resolve("data"), 6000));
|
|
96
|
+
});
|
|
97
|
+
const poller = new Poller(fetchFn, () => {}, 1000);
|
|
91
98
|
await poller.start();
|
|
92
|
-
|
|
99
|
+
// Only one fetch runs at a time — subsequent intervals are skipped until it completes
|
|
93
100
|
```
|