Skip to main content

Debouncing

Open in ChatGPT
25.11
Java API

Debouncing is a technique that delays executing an action until a specified time has elapsed since the last call. Each new call resets the timer. This is useful for scenarios like search-as-you-type, where you want to wait until the user stops typing before executing a search query.

Show Code

Create a Debouncer with a delay in seconds, then call run() with the action you want to debounce:

Debouncer debounce = new Debouncer(0.3f);

textField.onModify(e -> {
debounce.run(() -> search(textField.getText()));
});

In this example, the search() method is called only after the user stops typing for 300 milliseconds. Each keystroke resets the timer via the onModify event, so rapid typing won't trigger multiple searches.

How it works​

When you call run() with an action:

  1. If no action is pending, the Debouncer schedules the action to run after the delay
  2. If an action is already pending, the previous action is cancelled and the timer restarts with the new action
  3. Once the delay elapses without another call, the action executes

The Debouncer runs on the UI thread using webforJ's Interval mechanism, so you don't need to wrap UI updates in Environment.runLater().

Delay units

The delay parameter uses seconds as the unit, not milliseconds. Use 0.3f for 300 ms or 1.5f for 1.5 seconds.

Controlling execution​

The following methods can be used to more precisely handle the execution and use of the Debouncer:

Cancelling a pending action​

Use cancel() to stop a pending action from executing:

Debouncer debounce = new Debouncer(1f);

debounce.run(() -> saveDocument());

// User navigates away before save executes
debounce.cancel();
Cancelling pending debounces

Like intervals, it's good practice to cancel pending debounced actions when a component is destroyed. This prevents memory leaks and avoids errors from actions executing on destroyed components:

public class SearchPanel extends Composite<Div> {
private final Debouncer debounce = new Debouncer(0.3f);

@Override
protected void onDidDestroy() {
debounce.cancel();
}
}

Forcing immediate execution​

Use flush() to execute a pending action immediately:

Debouncer debounce = new Debouncer(0.5f);

textField.onModify(e -> {
debounce.run(() -> validateInput(textField.getText()));
});

// Force validation before form submission
submitButton.onClick(e -> {
debounce.flush();
if (isValid()) {
submitForm();
}
});

Checking pending status​

Use isPending() to verify if an action is waiting to execute:

Debouncer debounce = new Debouncer(0.3f);

if (debounce.isPending()) {
statusLabel.setText("Processing...");
}

Event level debouncing vs Debouncer​

webforJ provides two approaches to debouncing:

FeatureDebouncerElementEventOptions.setDebounce()
ScopeAny actionElement events only
LocationServer-sideClient-side
UnitSeconds (float)Milliseconds (int)
FlexibilityFull control with cancel/flushAutomatic with event

Use Debouncer when you need programmatic control over debouncing, such as cancelling or flushing pending actions. Use ElementEventOptions when you want simple client-side debouncing for element events without additional server round-trips.

// Using ElementEventOptions for client-side debouncing
ElementEventOptions options = new ElementEventOptions();
options.setDebounce(300);

element.addEventListener("input", e -> {
// This handler is debounced on the client
}, options);