All files / core/src/utils task.ts

100% Statements 36/36
100% Branches 9/9
100% Functions 3/3
100% Lines 36/36

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 811x                                                                         1x 88x 88x 88x 88x   88x 185x 182x 105x 105x   182x 182x   185x 107x 105x 105x 105x   105x   105x 105x 105x 105x 1x 1x 105x 107x 107x   185x 185x   88x 1x 1x 1x   88x 88x  
import { captureStack } from '../exception.js';
 
/**
 * Type definition for a task handler function.
 * @template T - The type of context data passed to the handler
 * @param init - The initial context when the task was first scheduled
 * @param current - The most recent context when the task was last scheduled
 * @returns A promise for async operations or void for sync operations
 */
export type TaskHandler<T> = (init: T, current: T) => Promise<void> | void;
 
/**
 * Type definition for a task scheduler function.
 * @template T - The type of context data that can be passed to the handler
 * @param fn - The task handler function to execute
 * @param context - Optional context data to pass to the handler
 */
export type TaskScheduler<T> = (fn: TaskHandler<T>, context?: T) => void;
 
/**
 * Type definition for a task destroyer function.
 * Used to clean up and cancel any pending tasks.
 */
export type TaskDestroyer = () => void;
 
/**
 * Creates a microtask scheduler that batches multiple calls into a single execution.
 *
 * This function returns a scheduler and destroyer pair that allows you to schedule
 * tasks which will be executed after a specified timeout. If multiple tasks are
 * scheduled within the timeout period, only the last one will be executed with
 * the initial and last context values.
 *
 * @template T - The type of context data that can be passed to the handler
 * @param timeout - The timeout in milliseconds before executing the task (default: 10ms)
 * @returns A tuple containing the scheduler and destroyer functions
 */
export function microtask<T = undefined>(timeout = 10): [TaskScheduler<T>, TaskDestroyer] {
  let initContext: T | undefined = undefined;
  let lastContext: T | undefined = undefined;
  let executor: TaskHandler<T> | undefined = undefined;
  let activeId: number | undefined = undefined;
 
  const schedule = (fn: TaskHandler<T>, context?: T) => {
    if (typeof context !== 'undefined') {
      if (typeof initContext === 'undefined') {
        initContext = context;
      }
 
      lastContext = context;
    }
 
    if (typeof executor !== 'function') {
      activeId = setTimeout(async () => {
        const execFn = executor;
        const initValue = initContext;
        const lastValue = lastContext;
 
        executor = initContext = lastContext = activeId = undefined;
 
        if (typeof execFn === 'function') {
          try {
            await execFn(initValue as T, lastValue as T);
          } catch (error) {
            captureStack.error.external('Scheduler execution failed.', error as Error);
          }
        }
      }, timeout) as never;
    }
 
    executor = fn;
  };
 
  const destroy = () => {
    clearTimeout(activeId);
    executor = initContext = lastContext = activeId = undefined;
  };
 
  return [schedule, destroy];
}