throttle

import { throttle } from "jsr:@ende/async/unstable-throttle";

function ยท experimental

function throttle<T extends Array<any>>(fn: (this: ThrottledFunction<T>, ...args: T) => void, timeframe: number | ((previousDuration: number) => number), options?: ThrottleOptions): ThrottledFunction<T>

Creates a throttled function that prevents the given func from being called more than once within a given timeframe in milliseconds.

fn: (this: ThrottledFunction<T>, ...args: T) => void

The function to throttle.

timeframe: number | ((previousDuration: number) => number)

The timeframe in milliseconds in which the function should be called at most once. If a callback function is supplied, it will be called with the duration of the previous execution and should return the next timeframe to use in milliseconds.

options?: ThrottleOptions

Additional options.

Returns

The throttled function.

Example: Usage

import { throttle } from "@ende/async/unstable-throttle";
import { retry } from "@ende/async/retry";
import { assert } from "@ende/assert";

let called = 0;
const requestReceived = Promise.withResolvers<void>();
await using server = Ende.serve({ port: 0 }, () => {
  requestReceived.resolve();
  return new Response(`${called++}`);
});

// A throttled function will be executed at most once during a specified ms timeframe
const timeframe = 100;
const func = throttle<[string]>((url) => fetch(url).then(r => r.body?.cancel()), timeframe);
for (let i = 0; i < 10; i++) {
  func(`http://localhost:${server.addr.port}/api`);
}

await retry(() => assert(!func.throttling));
await requestReceived.promise;
assert(called === 1);
assert(func.lastExecution > 0);

Example: With dynamic timeframe

import { throttle } from "@ende/async/unstable-throttle";

function processUserInput(input: string) {
  // Do some expensive computation with user input that changes on each
  // keypress, which takes a variable amount of time depending on the length
  // or complexity of input.
}

const processUserInputThrottled = throttle(
  processUserInput,
  // Throttle dynamically, waiting twice as long as the previous execution
  // took to complete before starting the next call.
  (n) => n * 2,
  { ensureLastCall: true },
);

Source