CxJS

debounce

import { debounce } from 'cx/util'; Copied

debounce delays function execution until after a specified time has elapsed since the last call. Useful for reducing the frequency of expensive operations like API calls triggered by user input.

<div controller={PageController}>
  <div style="display: flex; gap: 8px; align-items: center; margin-bottom: 16px">
    <TextField
      value={m.input}
      placeholder="Type to search..."
      style="width: 250px"
    />
    <Button onClick="searchNow">Search Now</Button>
    <Button onClick="reset">Reset</Button>
  </div>
  <div>
    <p>
      <strong>Input:</strong> <span text={m.input} />
    </p>
    <p>
      <strong>Debounced value:</strong> <span text={m.debouncedValue} />{" "}
      (updates 500ms after typing stops)
    </p>
    <p>
      <strong>Search executions:</strong> <span text={m.searchCount} />
    </p>
  </div>
</div>

Input:

Debounced value: (updates 500ms after typing stops)

Search executions: 0

Signature

function debounce<T extends (...args: any[]) => any>(
  callback: T,
  delay: number,
): DebouncedFunction<T>;

interface DebouncedFunction<T> {
  (...args: Parameters<T>): void;
  reset(...args: Parameters<T>): void;
}

Parameters

ParameterTypeDescription
callbackfunctionThe function to debounce.
delaynumberDelay in milliseconds.

Return Value

Returns a debounced function with a reset method to execute immediately.

Examples

Basic usage

const search = debounce((query: string) => {
  console.log("Searching for:", query);
  // API call here
}, 300);

// Rapid calls - only the last one executes
search("h"); // cancelled
search("he"); // cancelled
search("hel"); // cancelled
search("help"); // executes after 300ms

In a controller

class SearchController extends Controller {
  debouncedSearch: ReturnType<typeof debounce>;

  onInit() {
    this.debouncedSearch = debounce((query: string) => {
      this.store.set("results", this.performSearch(query));
    }, 500);
  }

  onQueryChange(e: any, { store }: any) {
    const query = store.get("query");
    this.debouncedSearch(query);
  }
}

Immediate execution with reset

const save = debounce((data) => {
  api.save(data);
}, 1000);

// User is typing - save is delayed
save(draft);

// User clicks "Save" button - execute immediately
save.reset(draft);

Window resize handler

const handleResize = debounce(() => {
  recalculateLayout();
}, 200);

window.addEventListener("resize", handleResize);

debounce vs throttle

FunctionBehavior
debounceWaits until calls stop, then executes once.
throttleExecutes at most once per interval while calls continue.
// Debounce: good for "when user stops typing"
const search = debounce(doSearch, 300);

// Throttle: good for "while user is scrolling"
const scroll = throttle(handleScroll, 100);

See Also