debounceDebouncer-KlasseRatenbegrenzung, Throttling und Debouncing sind drei verschiedene Ansätze zur Steuerung der Häufigkeit von Funktionsaufrufen. Jede Technik blockiert Ausführungen auf unterschiedliche Weise und macht sie "verlustbehaftet" – das bedeutet, dass einige Funktionsaufrufe nicht ausgeführt werden, wenn sie zu häufig angefordert werden. Das Verständnis, wann jeder Ansatz verwendet werden sollte, ist entscheidend für die Erstellung performanter und zuverlässiger Anwendungen. Dieser Leitfaden behandelt die Debouncing-Konzepte von TanStack Pacer.
Debouncing ist eine Technik, die die Ausführung einer Funktion verzögert, bis eine bestimmte Zeitspanne der Inaktivität eingetreten ist. Im Gegensatz zur Ratenbegrenzung, die Ausführungsstöße bis zu einem Limit zulässt, oder zum Throttling, das gleichmäßig verteilte Ausführungen gewährleistet, fasst Debouncing mehrere schnelle Funktionsaufrufe zu einer einzigen Ausführung zusammen, die erst nach Beendigung der Aufrufe stattfindet. Dies macht Debouncing ideal für die Verarbeitung von Ereignisstößen, bei denen Sie nur am Endzustand nach dem Abklingen der Aktivität interessiert sind.
Debouncing (wait: 3 ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Executed: ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ⏳ -> ✅ ❌ ⏳ -> ✅
[=================================================================]
^ Executes here after
3 ticks of no calls
[Burst of calls] [More calls] [Wait] [New burst]
No execution Resets timer [Delayed Execute] [Wait] [Delayed Execute]
Debouncing (wait: 3 ticks)
Timeline: [1 second per tick]
Calls: ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️
Executed: ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ⏳ -> ✅ ❌ ⏳ -> ✅
[=================================================================]
^ Executes here after
3 ticks of no calls
[Burst of calls] [More calls] [Wait] [New burst]
No execution Resets timer [Delayed Execute] [Wait] [Delayed Execute]
Debouncing ist besonders effektiv, wenn Sie auf eine "Pause" in der Aktivität warten möchten, bevor Sie handeln. Dies macht es ideal für die Verarbeitung von Benutzereingaben oder anderen schnell auslösenden Ereignissen, bei denen Sie nur am Endzustand interessiert sind.
Debouncing ist möglicherweise nicht die beste Wahl, wenn
TanStack Pacer bietet sowohl synchrone als auch asynchrone Debouncing-Funktionen. Dieser Leitfaden behandelt die synchrone Klasse Debouncer und die Funktion debounce. Für asynchrones Debouncing siehe den Leitfaden zu Asynchronem Debouncing.
Die Funktion debounce ist die einfachste Methode, jeder Funktion Debouncing hinzuzufügen.
import { debounce } from '@tanstack/pacer'
// Debounce search input to wait for user to stop typing
const debouncedSearch = debounce(
(searchTerm: string) => performSearch(searchTerm),
{
wait: 500, // Wait 500ms after last keystroke
}
)
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value)
})
import { debounce } from '@tanstack/pacer'
// Debounce search input to wait for user to stop typing
const debouncedSearch = debounce(
(searchTerm: string) => performSearch(searchTerm),
{
wait: 500, // Wait 500ms after last keystroke
}
)
searchInput.addEventListener('input', (e) => {
debouncedSearch(e.target.value)
})
Hinweis: Bei Verwendung von React bevorzugen Sie den Hook useDebounceCallback gegenüber der Funktion debounce für eine bessere Integration mit dem Lebenszyklus von React und automatische Bereinigung.
Debouncer-KlasseFür mehr Kontrolle über das Debouncing-Verhalten können Sie die Klasse Debouncer direkt verwenden.
import { Debouncer } from '@tanstack/pacer'
const searchDebouncer = new Debouncer(
(searchTerm: string) => performSearch(searchTerm),
{ wait: 500 }
)
// Access current state via TanStack Store
console.log(searchDebouncer.store.state.executionCount) // Number of successful executions
console.log(searchDebouncer.store.state.isPending) // Whether a call is pending
console.log(searchDebouncer.store.state.status) // Current execution status
// Update options dynamically
searchDebouncer.setOptions({ wait: 1000 }) // Increase wait time
// Cancel pending execution
searchDebouncer.cancel()
// Flush pending execution immediately
searchDebouncer.flush()
import { Debouncer } from '@tanstack/pacer'
const searchDebouncer = new Debouncer(
(searchTerm: string) => performSearch(searchTerm),
{ wait: 500 }
)
// Access current state via TanStack Store
console.log(searchDebouncer.store.state.executionCount) // Number of successful executions
console.log(searchDebouncer.store.state.isPending) // Whether a call is pending
console.log(searchDebouncer.store.state.status) // Current execution status
// Update options dynamically
searchDebouncer.setOptions({ wait: 1000 }) // Increase wait time
// Cancel pending execution
searchDebouncer.cancel()
// Flush pending execution immediately
searchDebouncer.flush()
Der synchrone Debouncer unterstützt sowohl führende als auch nachlaufende Ausführungen.
const debouncedFn = debounce(fn, {
wait: 500,
leading: true, // Execute on first call
trailing: true, // Execute after wait period
})
const debouncedFn = debounce(fn, {
wait: 500,
leading: true, // Execute on first call
trailing: true, // Execute after wait period
})
Gängige Muster
Der TanStack Pacer Debouncer hat absichtlich keine maxWait-Option wie andere Debouncing-Bibliotheken. Wenn Sie möchten, dass Ausführungen über einen längeren Zeitraum verteilt werden, sollten Sie stattdessen die Throttling-Technik verwenden.
Die Klasse Debouncer unterstützt das Aktivieren/Deaktivieren über die Option enabled. Mit der Methode setOptions können Sie den Debouncer jederzeit aktivieren/deaktivieren.
const debouncer = new Debouncer(fn, { wait: 500, enabled: false }) // Disable by default
debouncer.setOptions({ enabled: true }) // Enable at any time
const debouncer = new Debouncer(fn, { wait: 500, enabled: false }) // Disable by default
debouncer.setOptions({ enabled: true }) // Enable at any time
Die Option enabled kann auch eine Funktion sein, die einen booleschen Wert zurückgibt, was dynamisches Aktivieren/Deaktivieren basierend auf Laufzeitbedingungen ermöglicht.
const debouncer = new Debouncer(fn, {
wait: 500,
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
const debouncer = new Debouncer(fn, {
wait: 500,
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
Wenn Sie einen Framework-Adapter verwenden, bei dem die Debouncer-Optionen reaktiv sind, können Sie die Option enabled auf einen bedingten Wert setzen, um den Debouncer dynamisch zu aktivieren/deaktivieren.
// React example
const debouncer = useDebouncer(
setSearch,
{ wait: 500, enabled: searchInput.value.length > 3 } // Enable/disable based on input length IF using a framework adapter that supports reactive options
)
// React example
const debouncer = useDebouncer(
setSearch,
{ wait: 500, enabled: searchInput.value.length > 3 } // Enable/disable based on input length IF using a framework adapter that supports reactive options
)
Mehrere Optionen in der Debouncer unterstützen dynamische Werte durch Callback-Funktionen, die die Debouncer-Instanz erhalten.
const debouncer = new Debouncer(fn, {
// Dynamic wait time based on execution count
wait: (debouncer) => {
return debouncer.store.state.executionCount * 100 // Increase wait time with each execution
},
// Dynamic enabled state based on execution count
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
const debouncer = new Debouncer(fn, {
// Dynamic wait time based on execution count
wait: (debouncer) => {
return debouncer.store.state.executionCount * 100 // Increase wait time with each execution
},
// Dynamic enabled state based on execution count
enabled: (debouncer) => {
return debouncer.store.state.executionCount < 10 // Disable after 10 executions
}
})
Die folgenden Optionen unterstützen dynamische Werte
Dies ermöglicht ein ausgeklügeltes Debouncing-Verhalten, das sich an Laufzeitbedingungen anpasst.
Der synchrone Debouncer unterstützt den folgenden Callback.
const debouncer = new Debouncer(fn, {
wait: 500,
onExecute: (debouncer) => {
// Called after each successful execution
console.log('Function executed', debouncer.store.state.executionCount)
}
})
const debouncer = new Debouncer(fn, {
wait: 500,
onExecute: (debouncer) => {
// Called after each successful execution
console.log('Function executed', debouncer.store.state.executionCount)
}
})
Der Callback onExecute wird nach jeder erfolgreichen Ausführung der debounced Funktion aufgerufen und ist nützlich für die Verfolgung von Ausführungen, die Aktualisierung des UI-Zustands oder die Durchführung von Bereinigungsoperationen.
Der Debouncer unterstützt das "Leeren" ausstehender Ausführungen, um sie sofort auszulösen.
const debouncer = new Debouncer(fn, { wait: 1000 })
debouncer.maybeExecute('some-arg')
console.log(debouncer.store.state.isPending) // true
// Flush immediately instead of waiting
debouncer.flush()
console.log(debouncer.store.state.isPending) // false
const debouncer = new Debouncer(fn, { wait: 1000 })
debouncer.maybeExecute('some-arg')
console.log(debouncer.store.state.isPending) // true
// Flush immediately instead of waiting
debouncer.flush()
console.log(debouncer.store.state.isPending) // false
Die Klasse Debouncer verwendet TanStack Store für reaktives Zustandsmanagement und bietet Echtzeit-Zugriff auf Ausführungsstatus und Statistiken. Der gesamte Zustand wird in einem TanStack Store gespeichert und kann über debouncer.store.state abgerufen werden. Wenn Sie jedoch einen Framework-Adapter wie React oder Solid verwenden, sollten Sie den Zustand nicht von hier abrufen. Stattdessen rufen Sie den Zustand von debouncer.state ab und stellen eine Selektor-Callback als 3. Argument für den Hook useDebouncer zur Verfügung, um sich für die Zustandsverfolgung zu entscheiden, wie unten gezeigt.
Framework-Adapter unterstützen ein selector-Argument, das es Ihnen ermöglicht, anzugeben, welche Zustandsänderungen Neu-Renderings auslösen. Dies optimiert die Leistung, indem unnötige Neu-Renderings bei irrelevanten Zustandsänderungen verhindert werden.
Standardmäßig ist debouncer.state leer ({}), da der Selektor standardmäßig leer ist. Hier wird der reaktive Zustand von einem TanStack Store useStore gespeichert. Sie müssen sich für die Zustandsverfolgung entscheiden, indem Sie eine Selektorfunktion bereitstellen.
// Default behavior - no reactive state subscriptions
const debouncer = useDebouncer(fn, { wait: 500 })
console.log(debouncer.state) // {}
// Opt-in to re-render when isPending changes
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({ isPending: state.isPending })
)
console.log(debouncer.state.isPending) // Reactive value
// Multiple state properties
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
status: state.status
})
)
// Default behavior - no reactive state subscriptions
const debouncer = useDebouncer(fn, { wait: 500 })
console.log(debouncer.state) // {}
// Opt-in to re-render when isPending changes
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({ isPending: state.isPending })
)
console.log(debouncer.state.isPending) // Reactive value
// Multiple state properties
const debouncer = useDebouncer(
fn,
{ wait: 500 },
(state) => ({
isPending: state.isPending,
executionCount: state.executionCount,
status: state.status
})
)
Sie können Anfangswerte für den Zustand beim Erstellen eines Debouncers angeben. Dies wird häufig verwendet, um Zustände aus persistentem Speicher wiederherzustellen.
// Load initial state from localStorage
const savedState = localStorage.getItem('debouncer-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const debouncer = new Debouncer(fn, {
wait: 500,
key: 'search-debouncer',
initialState
})
// Load initial state from localStorage
const savedState = localStorage.getItem('debouncer-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const debouncer = new Debouncer(fn, {
wait: 500,
key: 'search-debouncer',
initialState
})
Der Store ist reaktiv und unterstützt Abonnements
const debouncer = new Debouncer(fn, { wait: 500 })
// Subscribe to state changes
const unsubscribe = debouncer.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
const debouncer = new Debouncer(fn, { wait: 500 })
// Subscribe to state changes
const unsubscribe = debouncer.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
Hinweis: Dies ist unnötig, wenn Sie einen Framework-Adapter verwenden, da der zugrunde liegende Hook useStore dies bereits tut. Sie können auch useStore von TanStack Store importieren und verwenden, um debouncer.store.state bei Bedarf in reaktiven Zustand mit einem benutzerdefinierten Selektor umzuwandeln.
Die DebouncerState beinhaltet
Jeder Framework-Adapter erstellt praktische Hooks und Funktionen um die Debouncer-Klassen. Hooks wie useDebouncer oder createDebouncer sind kleine Wrapper, die den Boilerplate-Code für einige gängige Anwendungsfälle reduzieren können.
Für asynchrones Debouncing (z. B. API-Aufrufe, asynchrone Operationen) siehe den Leitfaden zu Asynchronem Debouncing.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.