@@ -45,6 +45,25 @@ export interface GobanSocketOptions {
4545 /** Don't automatically send pings */
4646 dont_ping ?: boolean ;
4747
48+ /**
49+ * When true, pings are still sent (letting the browser throttle
50+ * naturally) but no timeout timers are armed and pong responses
51+ * are silently ignored (no latency/drift updates, no timeout
52+ * signals). Used when the tab is in the background so we keep the
53+ * connection alive through intermediaries without reacting to
54+ * unreliable timing measurements.
55+ */
56+ background_pinging ?: boolean ;
57+
58+ /**
59+ * Timestamp (ms since epoch). Pong responses whose originating
60+ * ping was sent before this time are silently discarded. Set to
61+ * Date.now() when transitioning from background to foreground so
62+ * that stale in-flight pongs from the background period don't
63+ * pollute latency measurements.
64+ */
65+ ignore_pongs_before ?: number ;
66+
4867 // Note: you can't turn off ping by setting ping interval to zero or undefined.
4968 ping_interval ?: number ; // milliseconds, applied if non-zero.
5069 timeout_delay ?: number ;
@@ -154,6 +173,20 @@ export class GobanSocket<
154173 this . socket = this . connect ( ) ;
155174
156175 this . on ( "net/pong" , ( { client, server } : { client : number ; server : number } ) => {
176+ // Ignore pongs from background pings: either we're still in
177+ // background mode, or this is a stale pong that arrived after
178+ // returning to the foreground.
179+ if (
180+ this . options . background_pinging ||
181+ ( this . options . ignore_pongs_before && client < this . options . ignore_pongs_before )
182+ ) {
183+ if ( this . timeout_timer ) {
184+ clearTimeout ( this . timeout_timer ) ;
185+ this . timeout_timer = undefined ;
186+ }
187+ return ;
188+ }
189+
157190 const now = Date . now ( ) ;
158191 const latency = now - client ;
159192 const drift = now - latency / 2 - server ;
@@ -162,8 +195,8 @@ export class GobanSocket<
162195 this . emit ( "latency" , latency , drift ) ;
163196 if ( this . timeout_timer ) {
164197 clearTimeout ( this . timeout_timer ) ;
198+ this . timeout_timer = undefined ;
165199 }
166- ///console.log("Pong:", this.url);
167200 } ) ;
168201 }
169202
@@ -183,6 +216,11 @@ export class GobanSocket<
183216 }
184217
185218 signalTimeout = ( ) => {
219+ // A timeout timer from the last foreground ping may fire after
220+ // we've transitioned to background mode -- ignore it.
221+ if ( this . options . background_pinging ) {
222+ return ;
223+ }
186224 this . emit ( "timeout" ) ;
187225 } ;
188226
@@ -198,7 +236,7 @@ export class GobanSocket<
198236 latency : this . latency ,
199237 } as DataArgument < SendProtocol [ "net/ping" ] > ) ;
200238
201- if ( this . options . timeout_delay ) {
239+ if ( this . options . timeout_delay && ! this . options . background_pinging ) {
202240 this . timeout_timer = setTimeout ( this . signalTimeout , this . options . timeout_delay ) ;
203241 }
204242
0 commit comments