perf(services): keep only the shared startup inventory read (J1)

Drop the startup deferral gate, its kill switch and the deferred loads:
they lowered renderer.ipcCallsToFirstCard but moved neither
spawnToFirstCardMs nor load->card beyond drift, and they grew
renderer.initialBytes. Keep the shared in-flight inventory read, inline
it in PlaylistsService with short property names, and copy the joiner's
result with structuredClone (the Electron renderer has it; the services
test setup polyfills it for jsdom).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
4grayandClaude Opus 5.5 committed 2026-09-29 08:59:35 +02:00
1 parent 0a5d5a984f
commit 8a33516c31
24 files changed
+64 -504

No files matched your search

@@ -7,11 +7,7 @@ import {
selectPlaylistsLoadingFlag,
} from '@iptvnator/m3u-state';
import { of, Subject } from 'rxjs';
import {
DatabaseService,
PlaylistsService,
StartupDeferralService,
} from '@iptvnator/services';
import { DatabaseService, PlaylistsService } from '@iptvnator/services';
import {
PlaybackPositionData,
Playlist,
@@ -274,30 +270,6 @@ describe('DashboardDataService', () => {
expect(service.dashboardReady()).toBe(false);
});
it('holds the page-entry reload until the first screen rendered', async () => {
let openGate!: () => void;
jest.spyOn(
TestBed.inject(StartupDeferralService),
'whenFirstContentRendered'
).mockReturnValue(new Promise<void>((resolve) => (openGate = resolve)));
const recent = jest
.spyOn(service, 'reloadGlobalRecentItems')
.mockResolvedValue(undefined);
const favorites = jest
.spyOn(service, 'reloadGlobalFavorites')
.mockResolvedValue(undefined);
const reload = service.reloadForPageEntry();
await Promise.resolve();
expect(recent).not.toHaveBeenCalled();
expect(favorites).not.toHaveBeenCalled();
openGate();
await reload;
expect(recent).toHaveBeenCalledTimes(1);
expect(favorites).toHaveBeenCalledTimes(1);
});
it('keeps dashboardReady false until xtream recently added finishes its first load', async () => {
expect(service.dashboardReady()).toBe(false);
@@ -20,7 +20,6 @@ import {
GlobalRecentlyAddedKind,
PlaylistsService,
RuntimeCapabilitiesService,
StartupDeferralService,
} from '@iptvnator/services';
import {
XTREAM_DATA_SOURCE,
@@ -117,7 +116,6 @@ export class DashboardDataService {
private readonly xtreamDataSource = inject(XTREAM_DATA_SOURCE);
private readonly playlistsService = inject(PlaylistsService);
private readonly runtime = inject(RuntimeCapabilitiesService);
private readonly startupDeferral = inject(StartupDeferralService);
private readonly ngZone = inject(NgZone);
private readonly translate = inject(TranslateService);
private readonly playbackPositions = inject(PORTAL_PLAYBACK_POSITIONS);
@@ -501,19 +499,6 @@ export class DashboardDataService {
readonly quickRecent = computed(() => this.recentPlaylists().slice(0, 4));
/**
* Page-entry reload of recent items and favorites. On launch it waits for
* the first rendered screen (journey J1) and the rails keep their
* skeletons meanwhile; later entries find the gate already open.
*/
async reloadForPageEntry(): Promise<void> {
await this.startupDeferral.whenFirstContentRendered();
await Promise.all([
this.reloadGlobalRecentItems(),
this.reloadGlobalFavorites(),
]);
}
async reloadGlobalRecentItems(): Promise<void> {
if (!this.globalRecentLoaded()) {
this.globalRecentLoadingState.set(true);