Skip to content

Commit ebd21ae

Browse files
committed
poll throttling + keep alive option
1 parent 95ca1e5 commit ebd21ae

File tree

5 files changed

+93
-21
lines changed

5 files changed

+93
-21
lines changed

packages/core/src/poll.ts

+39-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,48 @@
1-
class Poll {
2-
protected polls: VoidFunction[] = []
1+
import { PollOptions } from './types'
32

4-
add(interval: number, cb: VoidFunction): VoidFunction {
5-
const id = setInterval(cb, interval)
3+
export class Poll {
4+
protected id: number | null = null
5+
protected inBackground = false
6+
protected keepAlive = false
7+
protected currentInterval: number
8+
protected originalInterval: number
69

7-
const stop = () => clearInterval(id)
10+
constructor(interval: number, cb: VoidFunction, options: PollOptions) {
11+
this.keepAlive = options.keepAlive || false
812

9-
this.polls.push(stop)
13+
this.currentInterval = interval
14+
this.originalInterval = interval
1015

11-
return stop
16+
this.start(interval, cb)
1217
}
1318

14-
clear() {
15-
this.polls.forEach((stop) => stop())
19+
public stop() {
20+
if (this.id) {
21+
clearInterval(this.id)
22+
}
23+
}
24+
25+
public isInBackground(hidden: boolean) {
26+
this.inBackground = this.keepAlive ? false : hidden
1627

17-
this.polls = []
28+
if (this.inBackground) {
29+
// Throttle requests by 95% when the page is in the background
30+
this.currentInterval = Math.round(this.originalInterval / 0.95)
31+
} else {
32+
this.currentInterval = this.originalInterval
33+
}
1834
}
19-
}
2035

21-
export const poll = new Poll()
36+
protected start(interval: number, cb: VoidFunction) {
37+
this.id = window.setInterval(() => {
38+
if (this.currentInterval === interval) {
39+
cb()
40+
return
41+
}
42+
43+
// The visibility has changed, so we need to adjust the interval
44+
this.stop()
45+
this.start(this.currentInterval, cb)
46+
}, interval)
47+
}
48+
}

packages/core/src/polls.ts

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Poll } from './poll'
2+
import { PollOptions } from './types'
3+
4+
class Polls {
5+
protected polls: Poll[] = []
6+
7+
constructor() {
8+
this.setupVisibilityListener()
9+
}
10+
11+
public add(interval: number, cb: VoidFunction, options: PollOptions): VoidFunction {
12+
const poll = new Poll(interval, cb, options)
13+
14+
this.polls.push(poll)
15+
16+
return () => poll.stop()
17+
}
18+
19+
public clear() {
20+
this.polls.forEach((poll) => poll.stop())
21+
22+
this.polls = []
23+
}
24+
25+
protected setupVisibilityListener() {
26+
document.addEventListener(
27+
'visibilitychange',
28+
() => {
29+
this.polls.forEach((poll) => poll.isInBackground(document.hidden))
30+
},
31+
false,
32+
)
33+
}
34+
}
35+
36+
export const polls = new Polls()

packages/core/src/router.ts

+5-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { isFormData, objectToFormData } from './formData'
55
import { History } from './history'
66
import { navigationType } from './navigationType'
77
import { page as currentPage } from './page'
8-
import { poll } from './poll'
8+
import { polls } from './polls'
99
import { Request } from './request'
1010
import { RequestStream } from './requestStream'
1111
import { Scroll } from './scroll'
@@ -18,6 +18,7 @@ import {
1818
Method,
1919
Page,
2020
PendingVisit,
21+
PollOptions,
2122
ReloadOptions,
2223
RequestPayload,
2324
RouterInitParams,
@@ -49,7 +50,7 @@ export class Router {
4950
})
5051

5152
currentPage.on('newComponent', () => {
52-
poll.clear()
53+
polls.clear()
5354
this.loadDeferredProps()
5455
})
5556

@@ -123,8 +124,8 @@ export class Router {
123124
this.syncRequestStream.cancelInFlight()
124125
}
125126

126-
public poll(interval: number, options: ReloadOptions = {}): VoidFunction {
127-
return poll.add(interval, () => this.reload(options))
127+
public poll(interval: number, requestOptions: ReloadOptions = {}, options: PollOptions = {}): VoidFunction {
128+
return polls.add(interval, () => this.reload(requestOptions), { keepAlive: options.keepAlive || false })
128129
}
129130

130131
public visit(

packages/core/src/types.ts

+4
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ export type VisitOptions = Partial<
188188

189189
export type ReloadOptions = Omit<VisitOptions, 'preserveScroll' | 'preserveState'>
190190

191+
export type PollOptions = {
192+
keepAlive?: boolean
193+
}
194+
191195
export type VisitHelperOptions = Omit<VisitOptions, 'method' | 'data'>
192196

193197
export type RouterInitParams = {

playgrounds/vue3/resources/js/Pages/Poll.vue

+9-5
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,16 @@ const { stop } = usePoll(
4040
)
4141
4242
onMounted(() => {
43-
const stopUserPolling = router.poll(1000, {
44-
only: ['users'],
45-
onFinish() {
46-
userPollCount.value++
43+
const stopUserPolling = router.poll(
44+
1000,
45+
{
46+
only: ['users'],
47+
onFinish() {
48+
userPollCount.value++
49+
},
4750
},
48-
})
51+
{ keepAlive: true },
52+
)
4953
5054
setTimeout(() => {
5155
console.log('stopping user polling')

0 commit comments

Comments
 (0)