diff --git a/packages/studio/src/player/lib/thumbnailScheduler.test.ts b/packages/studio/src/player/lib/thumbnailScheduler.test.ts index 4705c70081..75469d3011 100644 --- a/packages/studio/src/player/lib/thumbnailScheduler.test.ts +++ b/packages/studio/src/player/lib/thumbnailScheduler.test.ts @@ -219,6 +219,26 @@ describe("ThumbnailScheduler", () => { expect(scheduler.getDiagnostics()).toMatchObject({ queued: 0, active: 0, leases: 0 }); }); + it("starts nothing that a release later in the same batch drops", async () => { + const scheduler = new ThumbnailScheduler( + resolveTimelineViewportBudgets({ concurrentVideoDecodes: 1 }), + ); + const video = (key: string, load: ThumbnailRequest["load"]) => + scheduler.acquire(request(key, load, "visible", { kind: "video" }), vi.fn()); + const activeLease = video("active", () => deferred().promise); + const droppedLoad = vi.fn(async () => result("dropped")); + const droppedLease = video("dropped", droppedLoad); + const keptLoad = vi.fn(async () => result("kept")); + video("kept", keptLoad); + + // A timeline jump unmounts its clips in one commit, the loading one first. + activeLease.release(); + droppedLease.release(); + await flush(); + expect(droppedLoad).not.toHaveBeenCalled(); + expect(keptLoad).toHaveBeenCalledTimes(1); + }); + it("frees an aborted job's slot at once, even when its loader ignores the abort", async () => { const scheduler = new ThumbnailScheduler( resolveTimelineViewportBudgets({ concurrentVideoDecodes: 1 }), @@ -231,7 +251,6 @@ describe("ThumbnailScheduler", () => { lease.release(); const nextLoad = vi.fn(async () => result("next")); scheduler.acquire(request("next", nextLoad, "visible", { kind: "video" }), vi.fn()); - await flush(); expect(nextLoad).toHaveBeenCalledTimes(1); }); diff --git a/packages/studio/src/player/lib/thumbnailScheduler.ts b/packages/studio/src/player/lib/thumbnailScheduler.ts index a0eb677465..d12a1e9575 100644 --- a/packages/studio/src/player/lib/thumbnailScheduler.ts +++ b/packages/studio/src/player/lib/thumbnailScheduler.ts @@ -316,7 +316,7 @@ export class ThumbnailScheduler { slotFree = true; this.activeByBucket[bucket]--; this.activeByKind[entry.request.kind]--; - this.pump(); + queueMicrotask(() => this.pump()); }; controller.signal.addEventListener("abort", freeSlot, { once: true }); this.notify(entry);