UNPKG

@artesoft/timeout-scheduler

Version:

A performance-oriented, freeze-proof scheduler that provides a priority-based task system to prevent UI blocking.

177 lines (176 loc) 6.5 kB
import { Observable } from 'rxjs'; /** * Defines the execution strategy for the scheduler. * - `throughput` (Default): Prioritizes maximum task execution speed by using * `requestAnimationFrame`. Ideal for UI animations and high-frequency updates. * - `responsiveness`: Prioritizes main-thread responsiveness by using * `scheduler.postTask` (if available) to yield frequently. */ export type SchedulingStrategy = 'throughput' | 'responsiveness'; /** * Defines the priority of a task. * - `user-visible`: High priority, runs sooner in a frame's budget. * - `background`: Low priority, runs only if time is left in a frame's budget. */ export type TaskPriority = 'user-visible' | 'background'; /** * Options for scheduling a specific task. */ export interface TaskOptions { /** The delay in milliseconds before the task should be executed. */ delay?: number; /** The priority of the task within the batching queue. */ priority?: TaskPriority; /** * Determines if the task should be batched and throttled by the scheduler. * - `true` (Default): The task is added to the frame loop and executed according * to the time budget. This is best for UI performance. * - `false`: The task bypasses the frame loop and uses a dedicated native timer. * This is required for networking libraries (e.g., Socket.io) that need exact timing * and cannot tolerate background throttling. */ batching?: boolean; } /** * Global configuration for the TimeoutScheduler instance. */ export interface SchedulerConfig { /** * The primary scheduling strategy to use when the page is visible. * @default 'throughput' */ primaryStrategy?: SchedulingStrategy; /** * If true, logs internal state changes to the console. * @default false */ loggingEnabled?: boolean; /** * (rAF Mode) If true, automatically adjusts the number of tasks per frame based on execution time. * @default true */ dynamicBudgetEnabled?: boolean; /** * (rAF Mode) The target execution time per frame in milliseconds. * @default 8 */ frameTimeBudgetMs?: number; /** * (rAF Mode) The initial number of tasks to execute per frame. * @default 50 */ initialTasksPerFrame?: number; /** * (rAF Mode) The maximum number of tasks allowed per frame. * @default 150 */ maxTasksPerFrame?: number; /** * The interval (in ms) for the background ticker when the tab is hidden. * Higher values reduce CPU usage; lower values improve background responsiveness. * @default 250 */ backgroundTickInterval?: number; } /** * Configuration for the `overrideTimeouts` method. */ export interface OverrideOptions { /** * A callback hook that allows you to determine the `TaskOptions` dynamically * whenever `setTimeout` is called. * * Use this to inspect the callback, delay, or arguments (or the Error stack) * to decide if a task should disable batching (e.g., for Socket.io). */ getTaskOptions?: (callback: Function, delay: number, args: any[]) => TaskOptions; } /** * A highly configurable, performance-oriented scheduler. * It intercepts or manages timer tasks to optimize main-thread usage, * providing frame-budgeting for UI work while allowing critical networking * tasks to bypass throttling. */ export declare class TimeoutScheduler { private readonly primaryStrategy; private readonly loggingEnabled; private readonly dynamicBudgetEnabled; private readonly frameTimeBudgetMs; private readonly maxTasksPerFrame; private readonly initialTasksPerFrame; private readonly backgroundTickInterval; private readonly originalSetTimeout; private readonly originalClearTimeout; private isOverridden; private taskIdCounter; private taskQueue; private readonly isPostTaskSupported; private currentSchedulingMode; private currentTasksPerFrame; private animationFrameId; private backgroundTickerId; /** Emits the current number of pending tasks (both batched and non-batched). */ readonly pendingTaskCount$: Observable<number>; private readonly pendingTaskCountSubject; /** * Constructs an instance of the TimeoutScheduler. * @param config Configuration options. */ constructor(config?: SchedulerConfig); /** * Schedules a task. * @param callback The function to execute. * @param options Configuration for delay, priority, and batching behavior. * @returns A unique Task ID (compatible with clearTimeout). */ scheduleTask(callback: (...args: any[]) => void, options?: TaskOptions): number; /** * Cancels a scheduled task, whether it is batched or non-batched. * @param taskId The ID returned by scheduleTask. */ cancelTask(taskId: number): void; /** * Overrides the global `window.setTimeout` and `window.clearTimeout`. * Allows providing a hook to dynamically configure task options (e.g., disabling batching). * @param options Configuration for the override behavior. */ overrideTimeouts(options?: OverrideOptions): void; /** * Restores the original `window.setTimeout` and `window.clearTimeout`. * Any pending batched tasks are rescheduled to run natively. */ restoreTimeouts(): void; /** * Destroys the scheduler instance, removing listeners and restoring globals. */ destroy(): void; /** * Handles visibility changes to switch between rAF (high perf) and setTimeout (background). */ private handleVisibilityChange; /** * Helper to execute a non-batched task immediately and remove it from the queue. */ private executeTaskImmediately; /** * Determines the correct scheduling loop based on tasks, strategy, and visibility. */ private startAppropriateTicker; /** * Stops all active loops (rAF, timeout) and aborts postTask controllers. */ private stopAllTickers; /** * Schedules a single batched task using scheduler.postTask. */ private runTaskWithPostTask; /** * The main processing loop used by `rAF` and `timeout` modes. * Batches tasks and respects the frame budget. */ private processRafQueue; /** * Adjusts the number of tasks allowed per frame based on how long the previous frame took. */ private adjustFrameBudget; }