perf(player): add idToIndex Map for O(1) track lookups
Replace all linear find/findIndex/some scans with a derived Map keyed by track.id. This makes currentTrack, currentIndex, hasTrack, add, playNext, remove, and addAll all O(1) for ID lookups.
This commit is contained in:
@@ -26,16 +26,26 @@ class PlayerStore {
|
|||||||
isMuted = $state(false);
|
isMuted = $state(false);
|
||||||
uiOpen = $state(false); // Mobile UI state
|
uiOpen = $state(false); // Mobile UI state
|
||||||
|
|
||||||
// Derived
|
// O(1) index: track.id → index in queue
|
||||||
currentTrack = $derived(
|
private idToIndex = $derived.by(() => {
|
||||||
this.currentId
|
const map = new Map<number, number>();
|
||||||
? (this.queue.find((t) => t.id === this.currentId) ?? null)
|
for (let i = 0; i < this.queue.length; i++) {
|
||||||
: null,
|
map.set(this.queue[i].id, i);
|
||||||
);
|
}
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
currentIndex = $derived(
|
// Derived
|
||||||
this.currentId ? this.queue.findIndex((t) => t.id === this.currentId) : -1,
|
currentTrack = $derived.by(() => {
|
||||||
);
|
if (this.currentId == null) return null;
|
||||||
|
const idx = this.idToIndex.get(this.currentId);
|
||||||
|
return idx !== undefined ? this.queue[idx] : null;
|
||||||
|
});
|
||||||
|
|
||||||
|
currentIndex = $derived.by(() => {
|
||||||
|
if (this.currentId == null) return -1;
|
||||||
|
return this.idToIndex.get(this.currentId) ?? -1;
|
||||||
|
});
|
||||||
|
|
||||||
displayQueue = $derived(
|
displayQueue = $derived(
|
||||||
this.isShuffled
|
this.isShuffled
|
||||||
@@ -46,7 +56,7 @@ class PlayerStore {
|
|||||||
);
|
);
|
||||||
|
|
||||||
hasTrack(id: number) {
|
hasTrack(id: number) {
|
||||||
return this.queue.some((t) => t.id === id);
|
return this.idToIndex.has(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@@ -105,9 +115,9 @@ class PlayerStore {
|
|||||||
// Actions
|
// Actions
|
||||||
|
|
||||||
add(track: Track, playNow = false) {
|
add(track: Track, playNow = false) {
|
||||||
const existingIdx = this.queue.findIndex((t) => t.id === track.id);
|
const exists = this.hasTrack(track.id);
|
||||||
|
|
||||||
if (existingIdx !== -1) {
|
if (exists) {
|
||||||
if (playNow) {
|
if (playNow) {
|
||||||
this.playNext(track);
|
this.playNext(track);
|
||||||
this.playId(track.id);
|
this.playId(track.id);
|
||||||
@@ -133,7 +143,7 @@ class PlayerStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
playNext(track: Track) {
|
playNext(track: Track) {
|
||||||
const existingIdx = this.queue.findIndex((t) => t.id === track.id);
|
const existingIdx = this.idToIndex.get(track.id) ?? -1;
|
||||||
const targetTrack = track;
|
const targetTrack = track;
|
||||||
|
|
||||||
if (existingIdx !== -1) {
|
if (existingIdx !== -1) {
|
||||||
@@ -173,7 +183,7 @@ class PlayerStore {
|
|||||||
const newTracks: Track[] = [];
|
const newTracks: Track[] = [];
|
||||||
for (const track of tracks) {
|
for (const track of tracks) {
|
||||||
// Check existence inline to avoid O(n) per-track via add()
|
// Check existence inline to avoid O(n) per-track via add()
|
||||||
if (!this.queue.some((t) => t.id === track.id)) {
|
if (!this.hasTrack(track.id)) {
|
||||||
newTracks.push(track);
|
newTracks.push(track);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -200,8 +210,8 @@ class PlayerStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
remove(id: number) {
|
remove(id: number) {
|
||||||
const idx = this.queue.findIndex((t) => t.id === id);
|
const idx = this.idToIndex.get(id);
|
||||||
if (idx === -1) return;
|
if (idx === undefined) return;
|
||||||
|
|
||||||
const wasCurrent = this.currentId === id;
|
const wasCurrent = this.currentId === id;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user