All files / utils tasks.ts

96% Statements 24/25
75% Branches 3/4
100% Functions 7/7
95.45% Lines 21/22

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 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99        94x                                                                             94x 2422x           2422x 2422x 2408x 2408x   2422x                   94x       5296x 5167x     129x     129x 65x   65x 53x 53x 53x                       94x 274x 274x    
/**
 * @module Utils
 */
 
import * as MH from "@lisn/globals/minification-helpers";
 
/**
 * @category Tasks
 */
export type SchedulerPostTaskOptions = {
  delay?: number;
  priority?: TaskPriority;
  signal?: AbortSignal;
};
 
/**
 * @category Tasks
 */
export type Scheduler = {
  postTask<T, P extends readonly unknown[] | []>(
    callback: (...params: P) => T,
    options?: SchedulerPostTaskOptions,
    ...args: P
  ): Promise<T>;
};
 
/**
 * @category Tasks
 */
export type TaskPriority = "user-blocking" | "user-visible" | "background";
 
/* eslint-disable-next-line no-var */
declare var scheduler: Scheduler;
 
/**
 * Schedules a task with high priority to be executed as soon as possible.
 *
 * It uses {@link https://developer.mozilla.org/en-US/docs/Web/API/Scheduler/postTask | Scheduler:postTask}
 * if available, otherwise falls back to
 * {@link https://developer.mozilla.org/en-US/docs/Web/API/MessageChannel | MessageChannel}.
 *
 * @category Tasks
 */
export const scheduleHighPriorityTask = (task: () => void) => {
  Iif (typeof scheduler !== "undefined") {
    scheduler.postTask(task, {
      priority: "user-blocking",
    });
  } else {
    // Fallback to MessageChannel
    const channel = new MessageChannel();
    channel.port1.onmessage = () => {
      channel.port1.close();
      task();
    };
    channel.port2.postMessage("");
  }
};
 
/**
 * Returns a wrapper around the given handler that is debounced by the given
 * debounce window.
 *
 * @category Tasks
 */
export const getDebouncedHandler = <Args extends unknown[]>(
  debounceWindow: number,
  handler: (...args: Args) => void,
) => {
  if (!debounceWindow) {
    return handler;
  }
 
  let timer: ReturnType<typeof setTimeout> | null = null;
  let lastArgs: Args;
 
  return (...args: Args) => {
    lastArgs = args;
 
    if (timer === null) {
      timer = MH.setTimer(async () => {
        await handler(...lastArgs);
        timer = null;
      }, debounceWindow);
    }
  };
};
 
/**
 * Returns a promise that resolves at least the given number of delay (in
 * milliseconds) later. Uses `setTimeout`.
 *
 * @category Tasks
 */
export const waitForDelay = (delay?: number) =>
  MH.newPromise<void>((resolve) => {
    MH.setTimer(resolve, delay);
  });