perf: pause background polling and animations when tab is hidden
- Background polling pauses when tab is not visible - Timer-based animations replaced with efficient frame-based updates - Reduced CPU usage when OpenChamber is in background
This commit is contained in:
@@ -405,6 +405,10 @@ export function DesktopHostSwitcherDialog({
|
||||
};
|
||||
void run();
|
||||
const interval = window.setInterval(() => {
|
||||
// Skip polling when tab is hidden to reduce background work
|
||||
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
void run();
|
||||
}, 1_500);
|
||||
|
||||
@@ -1255,6 +1259,10 @@ export function DesktopHostSwitcherButton({ headerIconButtonClass }: DesktopHost
|
||||
|
||||
void run();
|
||||
const interval = window.setInterval(() => {
|
||||
// Skip polling when tab is hidden to reduce background work
|
||||
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
void run();
|
||||
}, 10_000);
|
||||
return () => {
|
||||
|
||||
@@ -250,12 +250,41 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
|
||||
return;
|
||||
}
|
||||
|
||||
const intervalId = setInterval(() => {
|
||||
setChatRenderPreviewTick((prev) => (prev + 1) % 24);
|
||||
}, 420);
|
||||
// Use requestAnimationFrame for smoother animation without setInterval overhead
|
||||
let rafId: number | null = null;
|
||||
let lastTime = Date.now();
|
||||
|
||||
const tick = () => {
|
||||
const now = Date.now();
|
||||
// Update every ~420ms
|
||||
if (now - lastTime >= 420) {
|
||||
setChatRenderPreviewTick((prev) => (prev + 1) % 24);
|
||||
lastTime = now;
|
||||
}
|
||||
rafId = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
// Only run when visible
|
||||
if (typeof document === 'undefined' || document.visibilityState === 'visible') {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
const onVisibility = () => {
|
||||
if (document.visibilityState === 'visible' && rafId === null) {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
} else if (document.visibilityState !== 'visible' && rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', onVisibility);
|
||||
|
||||
return () => {
|
||||
clearInterval(intervalId);
|
||||
document.removeEventListener('visibilitychange', onVisibility);
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
}
|
||||
};
|
||||
}, [shouldAnimateChatPreview]);
|
||||
|
||||
|
||||
@@ -486,6 +486,9 @@ export const TunnelSettings: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
let rafId: number | null = null;
|
||||
let lastTime = Date.now();
|
||||
|
||||
const updateRemaining = () => {
|
||||
const remaining = tunnelInfo.bootstrapExpiresAt ? tunnelInfo.bootstrapExpiresAt - Date.now() : 0;
|
||||
if (remaining <= 0) {
|
||||
@@ -495,14 +498,79 @@ export const TunnelSettings: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const tick = () => {
|
||||
const now = Date.now();
|
||||
// Update only once per second
|
||||
if (now - lastTime >= 1_000) {
|
||||
updateRemaining();
|
||||
lastTime = now;
|
||||
}
|
||||
rafId = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
updateRemaining();
|
||||
const timer = window.setInterval(updateRemaining, 1000);
|
||||
return () => window.clearInterval(timer);
|
||||
|
||||
// Only run when visible
|
||||
if (typeof document === 'undefined' || document.visibilityState === 'visible') {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
const onVisibility = () => {
|
||||
if (document.visibilityState === 'visible' && rafId === null) {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
} else if (document.visibilityState !== 'visible' && rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', onVisibility);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', onVisibility);
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
}
|
||||
};
|
||||
}, [tunnelInfo?.bootstrapExpiresAt]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const timer = window.setInterval(() => setNowTs(Date.now()), 1000);
|
||||
return () => window.clearInterval(timer);
|
||||
// Use requestAnimationFrame for smoother updates without setInterval overhead
|
||||
let rafId: number | null = null;
|
||||
let lastTime = Date.now();
|
||||
|
||||
const tick = () => {
|
||||
const now = Date.now();
|
||||
// Update only once per second
|
||||
if (now - lastTime >= 1_000) {
|
||||
setNowTs(now);
|
||||
lastTime = now;
|
||||
}
|
||||
rafId = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
// Only run when visible
|
||||
if (typeof document === 'undefined' || document.visibilityState === 'visible') {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
const onVisibility = () => {
|
||||
if (document.visibilityState === 'visible' && rafId === null) {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
} else if (document.visibilityState !== 'visible' && rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', onVisibility);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('visibilitychange', onVisibility);
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -530,6 +598,10 @@ export const TunnelSettings: React.FC = () => {
|
||||
};
|
||||
|
||||
const timer = window.setInterval(() => {
|
||||
// Skip polling when tab is hidden
|
||||
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
void refreshSessions();
|
||||
}, 5000);
|
||||
|
||||
|
||||
@@ -305,6 +305,10 @@ export const RemoteInstancesPage: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
const interval = window.setInterval(() => {
|
||||
// Skip polling when tab is hidden to reduce background work
|
||||
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
void refreshStatuses();
|
||||
}, 2_000);
|
||||
return () => {
|
||||
@@ -313,11 +317,41 @@ export const RemoteInstancesPage: React.FC = () => {
|
||||
}, [refreshStatuses, selectedId]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const interval = window.setInterval(() => {
|
||||
setClockMs(Date.now());
|
||||
}, 1_000);
|
||||
// Use requestAnimationFrame for smoother clock updates without setInterval overhead
|
||||
let rafId: number | null = null;
|
||||
let lastTime = Date.now();
|
||||
|
||||
const tick = () => {
|
||||
const now = Date.now();
|
||||
// Update only once per second
|
||||
if (now - lastTime >= 1_000) {
|
||||
setClockMs(now);
|
||||
lastTime = now;
|
||||
}
|
||||
rafId = requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
// Only run when visible
|
||||
if (typeof document === 'undefined' || document.visibilityState === 'visible') {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
}
|
||||
|
||||
const onVisibility = () => {
|
||||
if (document.visibilityState === 'visible' && rafId === null) {
|
||||
rafId = requestAnimationFrame(tick);
|
||||
} else if (document.visibilityState !== 'visible' && rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
rafId = null;
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('visibilitychange', onVisibility);
|
||||
|
||||
return () => {
|
||||
window.clearInterval(interval);
|
||||
document.removeEventListener('visibilitychange', onVisibility);
|
||||
if (rafId !== null) {
|
||||
cancelAnimationFrame(rafId);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
@@ -525,6 +559,10 @@ export const RemoteInstancesPage: React.FC = () => {
|
||||
|
||||
void run();
|
||||
const interval = window.setInterval(() => {
|
||||
// Skip polling when tab is hidden
|
||||
if (typeof document !== 'undefined' && document.visibilityState !== 'visible') {
|
||||
return;
|
||||
}
|
||||
void run();
|
||||
}, 1_000);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user