wip: optimizations
This commit is contained in:
@@ -51,6 +51,7 @@ import { RoomsActions } from './store/rooms/rooms.actions';
|
||||
import { selectCurrentRoom } from './store/rooms/rooms.selectors';
|
||||
import { ROOM_URL_PATTERN } from './core/constants';
|
||||
import { clearStoredCurrentUserId, getStoredCurrentUserId } from './core/storage/current-user-storage';
|
||||
import { runWhenIdle } from './shared/rxjs';
|
||||
import {
|
||||
ThemeNodeDirective,
|
||||
ThemePickerOverlayComponent,
|
||||
@@ -234,10 +235,35 @@ export class App implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
// Wire the router subscription first so we never miss the initial
|
||||
// NavigationEnd while async bootstrap is still running.
|
||||
this.router.events.subscribe((evt) => {
|
||||
if (evt instanceof NavigationEnd) {
|
||||
const url = evt.urlAfterRedirects || evt.url;
|
||||
|
||||
this.currentRouteUrl.set(url);
|
||||
const roomMatch = url.match(ROOM_URL_PATTERN);
|
||||
const currentRoomId = roomMatch ? roomMatch[1] : null;
|
||||
|
||||
this.voiceSession.checkCurrentRoute(currentRoomId);
|
||||
}
|
||||
});
|
||||
|
||||
// Synchronous theme bootstrap so first paint has the right tokens.
|
||||
this.theme.initialize();
|
||||
|
||||
// Fire-and-forget work that must never block the render thread:
|
||||
// - desktop auto-updater handshake
|
||||
// - server-time offset (UI tolerates the local clock until it arrives)
|
||||
// - notifications subsystem (depends on savedRooms signal which is
|
||||
// populated by the rooms effect after dispatch)
|
||||
// - desktop deep-link bridge (only relevant after first paint)
|
||||
// - background presence + game activity loops
|
||||
void this.desktopUpdates.initialize();
|
||||
void this.kickOffBackgroundBootstrap();
|
||||
|
||||
// The only thing we genuinely must await before deciding which route
|
||||
// to show is the local database (it owns the persisted current user).
|
||||
let currentUserId = getStoredCurrentUserId();
|
||||
|
||||
await this.databaseService.initialize();
|
||||
@@ -251,18 +277,6 @@ export class App implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const apiBase = this.servers.getApiBaseUrl();
|
||||
|
||||
await this.timeSync.syncWithEndpoint(apiBase);
|
||||
} catch {}
|
||||
|
||||
await this.notifications.initialize();
|
||||
|
||||
await this.setupDesktopDeepLinks();
|
||||
|
||||
this.userStatus.start();
|
||||
this.gameActivity.start();
|
||||
const currentUrl = this.getCurrentRouteUrl();
|
||||
|
||||
if (!currentUserId) {
|
||||
@@ -299,17 +313,28 @@ export class App implements OnInit, OnDestroy {
|
||||
this.router.navigate(['/room', lastViewedChat.roomId], { replaceUrl: true }).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.router.events.subscribe((evt) => {
|
||||
if (evt instanceof NavigationEnd) {
|
||||
const url = evt.urlAfterRedirects || evt.url;
|
||||
/**
|
||||
* Runs services that the user does not actively wait on. Scheduled
|
||||
* through `requestIdleCallback` so they yield to the renderer until
|
||||
* the browser is idle, eliminating bootstrap stutter on Electron.
|
||||
*/
|
||||
private kickOffBackgroundBootstrap(): void {
|
||||
runWhenIdle(() => {
|
||||
try {
|
||||
const apiBase = this.servers.getApiBaseUrl();
|
||||
|
||||
this.currentRouteUrl.set(url);
|
||||
const roomMatch = url.match(ROOM_URL_PATTERN);
|
||||
const currentRoomId = roomMatch ? roomMatch[1] : null;
|
||||
|
||||
this.voiceSession.checkCurrentRoute(currentRoomId);
|
||||
void this.timeSync.syncWithEndpoint(apiBase).catch(() => {});
|
||||
} catch {
|
||||
// getApiBaseUrl can throw before endpoints are hydrated; ignore.
|
||||
}
|
||||
|
||||
void this.notifications.initialize().catch(() => {});
|
||||
void this.setupDesktopDeepLinks().catch(() => {});
|
||||
|
||||
this.userStatus.start();
|
||||
this.gameActivity.start();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user