# debounce

```ts
import { debounce } from 'cx/util';
```


`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.

```tsx
import { debounce } from "cx/util";
import { createModel } from "cx/data";
import { Controller } from "cx/ui";
import { TextField, Button } from "cx/widgets";

interface Model {
  input: string;
  debouncedValue: string;
  searchCount: number;
}

const m = createModel<Model>();

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

  onInit() {
    this.store.set(m.input, "");
    this.store.set(m.debouncedValue, "");
    this.store.set(m.searchCount, 0);

    this.debouncedSearch = debounce((value: string) => {
      this.store.set(m.debouncedValue, value);
      this.store.update(m.searchCount, (c) => c + 1);
    }, 500);

    // Subscribe to input changes
    this.addTrigger("inputChange", [m.input], (value: string) => {
      this.debouncedSearch(value);
    });
  }

  searchNow() {
    const value = this.store.get(m.input);
    this.debouncedSearch.reset(value);
  }

  reset() {
    this.store.set(m.input, "");
    this.store.set(m.debouncedValue, "");
    this.store.set(m.searchCount, 0);
  }
}

export default (
  <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>
);

```

## Signature

```ts
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

| Parameter  | Type       | Description               |
| ---------- | ---------- | ------------------------- |
| `callback` | `function` | The function to debounce. |
| `delay`    | `number`   | Delay in milliseconds.    |

## Return Value

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

## Examples

### Basic usage

```ts
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

```ts
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

```ts
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

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

window.addEventListener("resize", handleResize);
```

## debounce vs throttle

| Function   | Behavior                                                 |
| ---------- | -------------------------------------------------------- |
| `debounce` | Waits until calls stop, then executes once.              |
| `throttle` | Executes at most once per interval while calls continue. |

```ts
// 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

- [throttle](/docs/utilities/throttle) - Rate limit function calls