@estiva-app/platform 0.3.0 → 0.3.1
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/CHANGELOG.md +15 -0
- package/dist/refresh.d.ts +2 -0
- package/dist/refresh.d.ts.map +1 -1
- package/dist/refresh.js +60 -11
- package/dist/refresh.js.map +1 -1
- package/package.json +1 -1
- package/src/refresh.ts +67 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @estiva-app/platform
|
|
2
2
|
|
|
3
|
+
## 0.3.1
|
|
4
|
+
|
|
5
|
+
Subscribers on one interval share one timer (PER-6). No API change.
|
|
6
|
+
|
|
7
|
+
0.3.0 started a `setInterval` per subscriber, at the moment it subscribed, so
|
|
8
|
+
three views on one page on the same 10 s woke at three unrelated phases — Ship's
|
|
9
|
+
project page read every ~3 s, and never inside the 1 s merge. Now there is one
|
|
10
|
+
timer per distinct `intervalMs`, and every subscriber on it wakes in the same
|
|
11
|
+
tick.
|
|
12
|
+
|
|
13
|
+
- A subscriber that joined less than half an interval ago sits out a tick: its
|
|
14
|
+
caller has just done its own first read. Its first scheduled refresh comes
|
|
15
|
+
between 0.5× and 1.5× the interval after subscribing, then on the shared beat.
|
|
16
|
+
- Different intervals still have separate timers, and separate phases.
|
|
17
|
+
|
|
3
18
|
## 0.3.0
|
|
4
19
|
|
|
5
20
|
When a tab re-reads, and when the relay has asked it to wait (PER-13). Additive.
|
package/dist/refresh.d.ts
CHANGED
|
@@ -153,6 +153,8 @@ export interface RefreshScheduler {
|
|
|
153
153
|
/**
|
|
154
154
|
* Re-run `refresh` on focus, on becoming visible, and every `intervalMs`
|
|
155
155
|
* while visible. Never on subscribe — the caller owns its first read.
|
|
156
|
+
* Every subscriber on one `intervalMs` shares one timer and wakes in the same
|
|
157
|
+
* tick; the first scheduled refresh comes 0.5–1.5 intervals after subscribing.
|
|
156
158
|
* Returns an unsubscribe; calling it twice is harmless.
|
|
157
159
|
*/
|
|
158
160
|
subscribe(refresh: () => void | Promise<void>, options?: RefreshSubscription): () => void;
|
package/dist/refresh.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"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"}
|
package/dist/refresh.js
CHANGED
|
@@ -143,6 +143,7 @@ export function createRefreshScheduler(options) {
|
|
|
143
143
|
clearInterval: (handle) => host.clearInterval(handle),
|
|
144
144
|
};
|
|
145
145
|
const subscribers = new Set();
|
|
146
|
+
const groups = new Map();
|
|
146
147
|
let attached = false;
|
|
147
148
|
const visible = () => document.visibilityState === 'visible';
|
|
148
149
|
const tick = (subscriber) => {
|
|
@@ -173,18 +174,67 @@ export function createRefreshScheduler(options) {
|
|
|
173
174
|
if (visible())
|
|
174
175
|
fanOut();
|
|
175
176
|
};
|
|
177
|
+
/*
|
|
178
|
+
One timer per interval, not per subscriber (PER-6).
|
|
179
|
+
|
|
180
|
+
0.3.0 gave each subscriber its own `setInterval`, started when it
|
|
181
|
+
subscribed. Three views on one page, each on the same 10 s, therefore woke
|
|
182
|
+
at three unrelated phases — a read every three seconds or so, none of them
|
|
183
|
+
close enough to merge — and a page with a widget per section read "every
|
|
184
|
+
couple of seconds" at an interval nobody had chosen. Sharing the timer
|
|
185
|
+
puts every subscriber on an interval into the same wake-up.
|
|
186
|
+
|
|
187
|
+
A subscriber that joined less than half an interval ago sits the tick out:
|
|
188
|
+
its caller has just done its own first read, and a shared phase would
|
|
189
|
+
otherwise re-read it moments later. So the first scheduled refresh comes
|
|
190
|
+
between a half and one and a half intervals after subscribing, and every
|
|
191
|
+
one after that on the shared beat.
|
|
192
|
+
*/
|
|
193
|
+
const intervalTick = (group, intervalMs) => {
|
|
194
|
+
// Checked at fire time rather than started and stopped on every
|
|
195
|
+
// visibility change: a hidden tab has nothing on screen to be stale.
|
|
196
|
+
if (!visible())
|
|
197
|
+
return;
|
|
198
|
+
const now = clock.now();
|
|
199
|
+
for (const subscriber of [...group.members]) {
|
|
200
|
+
if (now - subscriber.joinedAt < intervalMs / 2)
|
|
201
|
+
continue;
|
|
202
|
+
tick(subscriber);
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
const join = (subscriber, intervalMs) => {
|
|
206
|
+
let group = groups.get(intervalMs);
|
|
207
|
+
if (!group) {
|
|
208
|
+
const created = { members: new Set(), timer: undefined };
|
|
209
|
+
created.timer = clock.setInterval(() => intervalTick(created, intervalMs), intervalMs);
|
|
210
|
+
groups.set(intervalMs, created);
|
|
211
|
+
group = created;
|
|
212
|
+
}
|
|
213
|
+
group.members.add(subscriber);
|
|
214
|
+
};
|
|
215
|
+
const leave = (subscriber) => {
|
|
216
|
+
if (subscriber.intervalMs === undefined)
|
|
217
|
+
return;
|
|
218
|
+
const group = groups.get(subscriber.intervalMs);
|
|
219
|
+
if (!group)
|
|
220
|
+
return;
|
|
221
|
+
group.members.delete(subscriber);
|
|
222
|
+
if (group.members.size === 0) {
|
|
223
|
+
clock.clearInterval(group.timer);
|
|
224
|
+
groups.delete(subscriber.intervalMs);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
176
227
|
return {
|
|
177
228
|
subscribe(refresh, { interval = true, intervalMs = defaultIntervalMs } = {}) {
|
|
178
|
-
const subscriber = {
|
|
229
|
+
const subscriber = {
|
|
230
|
+
refresh,
|
|
231
|
+
lastAt: 0,
|
|
232
|
+
joinedAt: clock.now(),
|
|
233
|
+
intervalMs: interval ? intervalMs : undefined,
|
|
234
|
+
};
|
|
179
235
|
subscribers.add(subscriber);
|
|
180
|
-
if (interval)
|
|
181
|
-
|
|
182
|
-
// visibility change: a hidden tab has nothing on screen to be stale.
|
|
183
|
-
subscriber.timer = clock.setInterval(() => {
|
|
184
|
-
if (visible())
|
|
185
|
-
tick(subscriber);
|
|
186
|
-
}, intervalMs);
|
|
187
|
-
}
|
|
236
|
+
if (interval)
|
|
237
|
+
join(subscriber, intervalMs);
|
|
188
238
|
if (!attached) {
|
|
189
239
|
// On first use and never at module scope, so importing registers
|
|
190
240
|
// nothing — and one pair of listeners however many subscribe.
|
|
@@ -195,8 +245,7 @@ export function createRefreshScheduler(options) {
|
|
|
195
245
|
return () => {
|
|
196
246
|
if (!subscribers.delete(subscriber))
|
|
197
247
|
return;
|
|
198
|
-
|
|
199
|
-
clock.clearInterval(subscriber.timer);
|
|
248
|
+
leave(subscriber);
|
|
200
249
|
if (subscribers.size === 0 && attached) {
|
|
201
250
|
document.removeEventListener('visibilitychange', onVisibility);
|
|
202
251
|
window.removeEventListener('focus', fanOut);
|
package/dist/refresh.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"refresh.js","sourceRoot":"","sources":["../src/refresh.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;;GAIG;AACH,MAAM,IAAI,GAAG,UAIZ,CAAA;AAED,kEAAkE;AAClE,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;IAChC,OAAO,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;AAC3E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc;IACxC,MAAM,KAAK,GAAG,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;IAChD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;AAChC,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,MAAM,kBAAkB,GAAG,MAAM,CAAA;AAExC;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAA;AAkDnC,MAAM,eAAe,GAAG,qBAAqB,CAAA;AAE7C,8EAA8E;AAC9E,SAAS,aAAa,CAAC,IAAa;IAClC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAA;IAC/D,MAAM,OAAO,GAAG,IAA2C,CAAA;IAC3D,IAAI,OAAO,CAAC,IAAI,KAAK,eAAe,IAAI,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAC3F,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;AACnE,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,UAA8B,EAAE;IAChE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAA;IAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,CAAC,EAAU,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,CAAA;IAC5G,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,IAAI,kBAAkB,CAAA;IACvE,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAA;IAC/B,IAAI,WAAW,GAAG,CAAC,CAAA;IAEnB,MAAM,MAAM,GAAG,CAAC,KAAa,EAAW,EAAE;QACxC,IAAI,KAAK,IAAI,WAAW;YAAE,OAAO,KAAK,CAAA;QACtC,WAAW,GAAG,KAAK,CAAA;QACnB,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IACD,MAAM,SAAS,GAAG,CAAC,KAAwB,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QACvC,wEAAwE;QACxE,kEAAkE;QAClE,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,KAAK,CAAC,CAAA;IACxC,CAAC,CAAA;IACD,OAAO,EAAE,gBAAgB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;IAE/C,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,GAAG,GAAG,EAAE,CAAC,CAAA;IAE1D,OAAO;QACL,eAAe,CAAC,MAAM;YACpB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,CAAC,IAAI,gBAAgB,CAAC,CAAA;YAC9E,MAAM,KAAK,GAAG,GAAG,EAAE,GAAG,IAAI,CAAA;YAC1B,IAAI,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClB,IAAI,CAAC;oBACH,OAAO,EAAE,WAAW,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC,CAAA;gBACxD,CAAC;gBAAC,MAAM,CAAC;oBACP,oEAAoE;gBACtE,CAAC;YACH,CAAC;YACD,OAAO,WAAW,EAAE,CAAA;QACtB,CAAC;QACD,WAAW;QACX,KAAK,CAAC,SAAS;YACb,KAAK,IAAI,IAAI,GAAG,WAAW,EAAE,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,WAAW,EAAE;gBAAE,MAAM,KAAK,CAAC,IAAI,CAAC,CAAA;QAClF,CAAC;QACD,KAAK;YACH,WAAW,GAAG,CAAC,CAAA;QACjB,CAAC;QACD,KAAK;YACH,OAAO,EAAE,mBAAmB,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QACpD,CAAC;KACF,CAAA;AACH,CAAC;AAsBD;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,CAAA;AAsCrC,MAAM,mBAAmB,GAAG,MAAM,CAAA;AAkBlC,MAAM,UAAU,sBAAsB,CAAC,OAAgC;IACrE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAA;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAA;IACnD,MAAM,iBAAiB,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAA;IACnE,MAAM,KAAK,GAAmB,OAAO,CAAC,KAAK,IAAI;QAC7C,0EAA0E;QAC1E,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;QACrB,WAAW,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,CAAC;QACnD,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;KACtD,CAAA;IACD,MAAM,WAAW,GAAG,IAAI,GAAG,EAAc,CAAA;IACzC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAyB,CAAA;IAC/C,IAAI,QAAQ,GAAG,KAAK,CAAA;IAEpB,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,QAAQ,CAAC,eAAe,KAAK,SAAS,CAAA;IAE5D,MAAM,IAAI,GAAG,CAAC,UAAsB,EAAE,EAAE;QACtC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;QACvB,IAAI,GAAG,GAAG,UAAU,CAAC,MAAM,GAAG,OAAO;YAAE,OAAM;QAC7C,4EAA4E;QAC5E,wEAAwE;QACxE,4EAA4E;QAC5E,4EAA4E;QAC5E,IAAI,MAAM,IAAI,MAAM,CAAC,WAAW,EAAE,GAAG,CAAC;YAAE,OAAM;QAC9C,UAAU,CAAC,MAAM,GAAG,GAAG,CAAA;QACvB,IAAI,CAAC;YACH,sEAAsE;YACtE,uEAAuE;YACvE,KAAK,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;IACH,CAAC,CAAA;IACD,MAAM,MAAM,GAAG,GAAG,EAAE;QAClB,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,WAAW,CAAC;YAAE,IAAI,CAAC,UAAU,CAAC,CAAA;IAC7D,CAAC,CAAA;IACD,MAAM,YAAY,GAAG,GAAG,EAAE;QACxB,IAAI,OAAO,EAAE;YAAE,MAAM,EAAE,CAAA;IACzB,CAAC,CAAA;IAED;;;;;;;;;;;;;;;MAeE;IACF,MAAM,YAAY,GAAG,CAAC,KAAoB,EAAE,UAAkB,EAAE,EAAE;QAChE,gEAAgE;QAChE,qEAAqE;QACrE,IAAI,CAAC,OAAO,EAAE;YAAE,OAAM;QACtB,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;QACvB,KAAK,MAAM,UAAU,IAAI,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,IAAI,GAAG,GAAG,UAAU,CAAC,QAAQ,GAAG,UAAU,GAAG,CAAC;gBAAE,SAAQ;YACxD,IAAI,CAAC,UAAU,CAAC,CAAA;QAClB,CAAC;IACH,CAAC,CAAA;IACD,MAAM,IAAI,GAAG,CAAC,UAAsB,EAAE,UAAkB,EAAE,EAAE;QAC1D,IAAI,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,OAAO,GAAkB,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;YACvE,OAAO,CAAC,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,EAAE,UAAU,CAAC,CAAA;YACtF,MAAM,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;YAC/B,KAAK,GAAG,OAAO,CAAA;QACjB,CAAC;QACD,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IAC/B,CAAC,CAAA;IACD,MAAM,KAAK,GAAG,CAAC,UAAsB,EAAE,EAAE;QACvC,IAAI,UAAU,CAAC,UAAU,KAAK,SAAS;YAAE,OAAM;QAC/C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;QAC/C,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QAChC,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;YAChC,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;QACtC,CAAC;IACH,CAAC,CAAA;IAED,OAAO;QACL,SAAS,CAAC,OAAO,EAAE,EAAE,QAAQ,GAAG,IAAI,EAAE,UAAU,GAAG,iBAAiB,EAAE,GAAG,EAAE;YACzE,MAAM,UAAU,GAAe;gBAC7B,OAAO;gBACP,MAAM,EAAE,CAAC;gBACT,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE;gBACrB,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;aAC9C,CAAA;YACD,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;YAC3B,IAAI,QAAQ;gBAAE,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,CAAA;YAC1C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,iEAAiE;gBACjE,8DAA8D;gBAC9D,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAA;gBAC3D,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;gBACxC,QAAQ,GAAG,IAAI,CAAA;YACjB,CAAC;YACD,OAAO,GAAG,EAAE;gBACV,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;oBAAE,OAAM;gBAC3C,KAAK,CAAC,UAAU,CAAC,CAAA;gBACjB,IAAI,WAAW,CAAC,IAAI,KAAK,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACvC,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAA;oBAC9D,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;oBAC3C,QAAQ,GAAG,KAAK,CAAA;gBAClB,CAAC;YACH,CAAC,CAAA;QACH,CAAC;KACF,CAAA;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@estiva-app/platform",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Browser lifecycle two Estiva apps share: the one live relay socket a tab should hold, its credential read per connect, the network coming back, and when a tab re-reads.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/refresh.ts
CHANGED
|
@@ -238,6 +238,8 @@ export interface RefreshScheduler {
|
|
|
238
238
|
/**
|
|
239
239
|
* Re-run `refresh` on focus, on becoming visible, and every `intervalMs`
|
|
240
240
|
* while visible. Never on subscribe — the caller owns its first read.
|
|
241
|
+
* Every subscriber on one `intervalMs` shares one timer and wakes in the same
|
|
242
|
+
* tick; the first scheduled refresh comes 0.5–1.5 intervals after subscribing.
|
|
241
243
|
* Returns an unsubscribe; calling it twice is harmless.
|
|
242
244
|
*/
|
|
243
245
|
subscribe(refresh: () => void | Promise<void>, options?: RefreshSubscription): () => void
|
|
@@ -249,6 +251,15 @@ interface Subscriber {
|
|
|
249
251
|
refresh: () => void | Promise<void>
|
|
250
252
|
/** When this subscriber last ran. Merge and pause are judged per subscriber. */
|
|
251
253
|
lastAt: number
|
|
254
|
+
/** When it subscribed — its caller's own first read, which this never sees. */
|
|
255
|
+
joinedAt: number
|
|
256
|
+
/** The interval it ticks on, or `undefined` for focus and visibility only. */
|
|
257
|
+
intervalMs: number | undefined
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/** Every subscriber on one interval, and the one timer they share (PER-6). */
|
|
261
|
+
interface IntervalGroup {
|
|
262
|
+
members: Set<Subscriber>
|
|
252
263
|
timer: unknown
|
|
253
264
|
}
|
|
254
265
|
|
|
@@ -263,6 +274,7 @@ export function createRefreshScheduler(options: RefreshSchedulerOptions): Refres
|
|
|
263
274
|
clearInterval: (handle) => host.clearInterval(handle),
|
|
264
275
|
}
|
|
265
276
|
const subscribers = new Set<Subscriber>()
|
|
277
|
+
const groups = new Map<number, IntervalGroup>()
|
|
266
278
|
let attached = false
|
|
267
279
|
|
|
268
280
|
const visible = () => document.visibilityState === 'visible'
|
|
@@ -291,17 +303,63 @@ export function createRefreshScheduler(options: RefreshSchedulerOptions): Refres
|
|
|
291
303
|
if (visible()) fanOut()
|
|
292
304
|
}
|
|
293
305
|
|
|
306
|
+
/*
|
|
307
|
+
One timer per interval, not per subscriber (PER-6).
|
|
308
|
+
|
|
309
|
+
0.3.0 gave each subscriber its own `setInterval`, started when it
|
|
310
|
+
subscribed. Three views on one page, each on the same 10 s, therefore woke
|
|
311
|
+
at three unrelated phases — a read every three seconds or so, none of them
|
|
312
|
+
close enough to merge — and a page with a widget per section read "every
|
|
313
|
+
couple of seconds" at an interval nobody had chosen. Sharing the timer
|
|
314
|
+
puts every subscriber on an interval into the same wake-up.
|
|
315
|
+
|
|
316
|
+
A subscriber that joined less than half an interval ago sits the tick out:
|
|
317
|
+
its caller has just done its own first read, and a shared phase would
|
|
318
|
+
otherwise re-read it moments later. So the first scheduled refresh comes
|
|
319
|
+
between a half and one and a half intervals after subscribing, and every
|
|
320
|
+
one after that on the shared beat.
|
|
321
|
+
*/
|
|
322
|
+
const intervalTick = (group: IntervalGroup, intervalMs: number) => {
|
|
323
|
+
// Checked at fire time rather than started and stopped on every
|
|
324
|
+
// visibility change: a hidden tab has nothing on screen to be stale.
|
|
325
|
+
if (!visible()) return
|
|
326
|
+
const now = clock.now()
|
|
327
|
+
for (const subscriber of [...group.members]) {
|
|
328
|
+
if (now - subscriber.joinedAt < intervalMs / 2) continue
|
|
329
|
+
tick(subscriber)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
const join = (subscriber: Subscriber, intervalMs: number) => {
|
|
333
|
+
let group = groups.get(intervalMs)
|
|
334
|
+
if (!group) {
|
|
335
|
+
const created: IntervalGroup = { members: new Set(), timer: undefined }
|
|
336
|
+
created.timer = clock.setInterval(() => intervalTick(created, intervalMs), intervalMs)
|
|
337
|
+
groups.set(intervalMs, created)
|
|
338
|
+
group = created
|
|
339
|
+
}
|
|
340
|
+
group.members.add(subscriber)
|
|
341
|
+
}
|
|
342
|
+
const leave = (subscriber: Subscriber) => {
|
|
343
|
+
if (subscriber.intervalMs === undefined) return
|
|
344
|
+
const group = groups.get(subscriber.intervalMs)
|
|
345
|
+
if (!group) return
|
|
346
|
+
group.members.delete(subscriber)
|
|
347
|
+
if (group.members.size === 0) {
|
|
348
|
+
clock.clearInterval(group.timer)
|
|
349
|
+
groups.delete(subscriber.intervalMs)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
294
353
|
return {
|
|
295
354
|
subscribe(refresh, { interval = true, intervalMs = defaultIntervalMs } = {}) {
|
|
296
|
-
const subscriber: Subscriber = {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
subscriber.timer = clock.setInterval(() => {
|
|
302
|
-
if (visible()) tick(subscriber)
|
|
303
|
-
}, intervalMs)
|
|
355
|
+
const subscriber: Subscriber = {
|
|
356
|
+
refresh,
|
|
357
|
+
lastAt: 0,
|
|
358
|
+
joinedAt: clock.now(),
|
|
359
|
+
intervalMs: interval ? intervalMs : undefined,
|
|
304
360
|
}
|
|
361
|
+
subscribers.add(subscriber)
|
|
362
|
+
if (interval) join(subscriber, intervalMs)
|
|
305
363
|
if (!attached) {
|
|
306
364
|
// On first use and never at module scope, so importing registers
|
|
307
365
|
// nothing — and one pair of listeners however many subscribe.
|
|
@@ -311,7 +369,7 @@ export function createRefreshScheduler(options: RefreshSchedulerOptions): Refres
|
|
|
311
369
|
}
|
|
312
370
|
return () => {
|
|
313
371
|
if (!subscribers.delete(subscriber)) return
|
|
314
|
-
|
|
372
|
+
leave(subscriber)
|
|
315
373
|
if (subscribers.size === 0 && attached) {
|
|
316
374
|
document.removeEventListener('visibilitychange', onVisibility)
|
|
317
375
|
window.removeEventListener('focus', fanOut)
|