Skip to content

Commit cbb71a7

Browse files
committed
Avoid showing RTC disconnect dialog on expected request failure during refresh
1 parent 7b1131b commit cbb71a7

File tree

1 file changed

+30
-3
lines changed

1 file changed

+30
-3
lines changed

packages/sync/src/providers/http-polling/polling-manager.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,9 +240,24 @@ function processDocUpdate(
240240
}
241241

242242
let isPolling = false;
243+
let isUnloadPending = false;
243244
let pollInterval = POLLING_INTERVAL_IN_MS;
244245
let pageHideListenerRegistered = false;
245246

247+
/**
248+
* Mark that a page unload has been requested. This fires on
249+
* `beforeunload` which happens before the browser aborts in-flight
250+
* fetches, allowing us to distinguish poll failures caused by
251+
* navigation from genuine server errors in the catch block.
252+
*
253+
* If the user cancels the unload (e.g. by dismissing a "Save Changes?" dialog),
254+
* the flag is reset at the start of the next poll cycle so that polling can
255+
* resume.
256+
*/
257+
function handleBeforeUnload(): void {
258+
isUnloadPending = true;
259+
}
260+
246261
/**
247262
* Send a disconnect signal for all registered rooms when the page is
248263
* being unloaded. Uses `sendBeacon` so the request survives navigation.
@@ -270,6 +285,11 @@ function poll(): void {
270285
return;
271286
}
272287

288+
// Reset the unloading flag at the start of each poll cycle so
289+
// it doesn't permanently suppress disconnect after the user
290+
// cancels a beforeunload dialog.
291+
isUnloadPending = false;
292+
273293
// Emit 'connecting' status.
274294
roomStates.forEach( ( state ) => {
275295
state.onStatusChange( { status: 'connecting' } );
@@ -371,9 +391,14 @@ function poll(): void {
371391
);
372392
}
373393

374-
roomStates.forEach( ( state ) => {
375-
state.onStatusChange( { status: 'disconnected' } );
376-
} );
394+
// Don't report disconnected status when the request was aborted
395+
// due to page unload (e.g. during a refresh) to avoid briefly
396+
// flashing the disconnect dialog before the new page loads.
397+
if ( ! isUnloadPending ) {
398+
roomStates.forEach( ( state ) => {
399+
state.onStatusChange( { status: 'disconnected' } );
400+
} );
401+
}
377402
}
378403

379404
setTimeout( poll, pollInterval );
@@ -441,6 +466,7 @@ function registerRoom( {
441466
roomStates.set( room, roomState );
442467

443468
if ( ! pageHideListenerRegistered ) {
469+
window.addEventListener( 'beforeunload', handleBeforeUnload );
444470
window.addEventListener( 'pagehide', handlePageHide );
445471
pageHideListenerRegistered = true;
446472
}
@@ -471,6 +497,7 @@ function unregisterRoom( room: string ): void {
471497
}
472498

473499
if ( roomStates.size === 0 && pageHideListenerRegistered ) {
500+
window.removeEventListener( 'beforeunload', handleBeforeUnload );
474501
window.removeEventListener( 'pagehide', handlePageHide );
475502
pageHideListenerRegistered = false;
476503
}

0 commit comments

Comments
 (0)