UNPKG

wavesurfer.js

Version:
76 lines (75 loc) 2.34 kB
/** * RenderScheduler batches multiple render requests into a single frame using requestAnimationFrame. * This prevents multiple state changes from triggering redundant renders. */ export class RenderScheduler { constructor() { this.pendingRender = false; this.rafId = null; } /** * Schedule a render to occur on the next animation frame. * If a render is already scheduled, this is a no-op. * * @param renderFn - The function to call to perform the render * @param priority - Render priority (high = immediate, normal/low = batched) * * @example * ```typescript * const scheduler = new RenderScheduler() * * // Multiple calls in same frame = single render * scheduler.scheduleRender(() => draw()) * scheduler.scheduleRender(() => draw()) // no-op * scheduler.scheduleRender(() => draw()) // no-op * ``` */ scheduleRender(renderFn, priority = 'normal') { // High priority renders happen immediately if (priority === 'high') { this.flushRender(renderFn); return; } // If already scheduled, don't schedule again if (this.pendingRender) return; this.pendingRender = true; this.rafId = requestAnimationFrame(() => { try { renderFn(); } finally { // Always clean up, even if render throws this.pendingRender = false; this.rafId = null; } }); } /** * Cancel any pending render request. * Useful when unmounting or destroying components. */ cancelRender() { if (this.rafId !== null) { cancelAnimationFrame(this.rafId); this.rafId = null; this.pendingRender = false; } } /** * Force an immediate synchronous render, canceling any pending batched render. * Use for high-priority updates like cursor during playback, or for testing. * * @param renderFn - The function to call to perform the render */ flushRender(renderFn) { this.cancelRender(); renderFn(); } /** * Check if a render is currently scheduled. */ isPending() { return this.pendingRender; } }