Debouncing
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
- Java
Basic usage
The Debouncer class provides a simple way to debounce actions. 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:
- If no action is pending, the
Debouncerschedules the action to run after the delay - If an action is already pending, the previous action is cancelled and the timer restarts with the new action
- 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().
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();
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:
| Feature | Debouncer | ElementEventOptions.setDebounce() |
|---|---|---|
| Scope | Any action | Element events only |
| Location | Server-side | Client-side |
| Unit | Seconds (float) | Milliseconds (int) |
| Flexibility | Full control with cancel/flush | Automatic 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);