Framework
Version
Debouncer API Referenz
Throttler API Referenz
Rate Limiter API Referenz
Queue API Referenz
Batcher API Referenz

Async Rate Limiting-Anleitung

Alle Kernkonzepte aus dem Rate Limiting Guide gelten auch für die asynchrone Ratenbegrenzung.

Wann asynchrone Ratenbegrenzung zu verwenden ist

Normalerweise können Sie einfach den normalen synchronen Ratenbegrenzer verwenden, und er funktioniert mit asynchronen Funktionen. Für fortgeschrittene Anwendungsfälle, z. B. wenn Sie den Rückgabewert einer ratenbegrenzten Funktion verwenden möchten (anstatt nur einen setState-Seiteneffekt aufzurufen) oder Ihre Fehlerbehandlungslogik in den Ratenbegrenzer legen möchten, können Sie den asynchronen Ratenbegrenzer verwenden.

Asynchrone Ratenbegrenzung in TanStack Pacer

TanStack Pacer bietet asynchrone Ratenbegrenzung über die Klasse AsyncRateLimiter und die Funktion asyncRateLimit.

Grundlegendes Beispiel

Hier ist ein grundlegendes Beispiel, das zeigt, wie der asynchrone Ratenbegrenzer für einen API-Vorgang verwendet wird

ts
const rateLimitedApi = asyncRateLimit(
  async (id: string) => {
    const response = await fetch(`/api/data/${id}`)
    return response.json()
  },
  {
    limit: 5,
    window: 1000,
    onExecute: (limiter) => {
      console.log('API call succeeded:', limiter.store.state.successCount)
    },
    onReject: (limiter) => {
      console.log(`Rate limit exceeded. Try again in ${limiter.getMsUntilNextWindow()}ms`)
    },
    onError: (error, limiter) => {
      console.error('API call failed:', error)
    }
  }
)

// Usage
try {
  const result = await rateLimitedApi('123')
  // Handle successful result
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('API call failed:', error)
}
const rateLimitedApi = asyncRateLimit(
  async (id: string) => {
    const response = await fetch(`/api/data/${id}`)
    return response.json()
  },
  {
    limit: 5,
    window: 1000,
    onExecute: (limiter) => {
      console.log('API call succeeded:', limiter.store.state.successCount)
    },
    onReject: (limiter) => {
      console.log(`Rate limit exceeded. Try again in ${limiter.getMsUntilNextWindow()}ms`)
    },
    onError: (error, limiter) => {
      console.error('API call failed:', error)
    }
  }
)

// Usage
try {
  const result = await rateLimitedApi('123')
  // Handle successful result
} catch (error) {
  // Handle errors if no onError handler was provided
  console.error('API call failed:', error)
}

Hinweis: Bei der Verwendung von React bevorzugen Sie den Hook useAsyncRateLimitedCallback gegenüber der Funktion asyncRateLimit, um eine bessere Integration mit dem Lebenszyklus von React und der automatischen Bereinigung zu gewährleisten.

Wesentliche Unterschiede zur synchronen Ratenbegrenzung

1. Rückgabewertbehandlung

Im Gegensatz zum synchronen Ratenbegrenzer, der einen booleschen Wert zurückgibt, der den Erfolg anzeigt, ermöglicht die asynchrone Version das Erfassen und Verwenden des Rückgabewerts Ihrer ratenbegrenzten Funktion. Die Methode maybeExecute gibt ein Promise zurück, das mit dem Rückgabewert der Funktion aufgelöst wird, sodass Sie auf das Ergebnis warten und es entsprechend behandeln können.

2. Fehlerbehandlung

Der asynchrone Ratenbegrenzer bietet robuste Fehlerbehandlungsfunktionen

  • Wenn Ihre ratenbegrenzte Funktion einen Fehler auslöst und kein onError-Handler bereitgestellt wird, wird der Fehler ausgelöst und an den Aufrufer weitergegeben
  • Wenn Sie einen onError-Handler bereitstellen, werden Fehler abgefangen und an den Handler übergeben, anstatt ausgelöst zu werden.
  • Die Option throwOnError kann verwendet werden, um das Fehler-Auslöseverhalten zu steuern
    • Wenn true (Standard, wenn kein onError-Handler vorhanden ist), werden Fehler ausgelöst
    • Wenn false (Standard, wenn ein onError-Handler vorhanden ist), werden Fehler geschluckt
    • Kann explizit gesetzt werden, um diese Standardeinstellungen zu überschreiben
  • Sie können Fehlerzähler mit limiter.store.state.errorCount verfolgen und den Ausführungsstatus mit limiter.store.state.isExecuting überprüfen
  • Der Ratenbegrenzer behält seinen Zustand bei und kann auch nach einem Fehler weiter verwendet werden
  • Ratenlimit-Zurückweisungen (wenn das Limit überschritten wird) werden getrennt von Ausführungsfehlern über den onReject-Handler behandelt

3. Unterschiedliche Callbacks

Die AsyncRateLimiter unterstützt die folgenden Callbacks

  • onSuccess: Wird nach jeder erfolgreichen Ausführung aufgerufen und liefert das Ergebnis, die aufgerufenen Argumente und die Ratenbegrenzer-Instanz
  • onSettled: Wird nach jeder Ausführung (Erfolg oder Fehler) aufgerufen und liefert die aufgerufenen Argumente und die Ratenbegrenzer-Instanz
  • onError: Wird aufgerufen, wenn die asynchrone Funktion einen Fehler auslöst, und liefert den Fehler, die Argumente, die den Fehler verursacht haben, und die Ratenbegrenzer-Instanz

Sowohl der asynchrone als auch der synchrone Ratenbegrenzer unterstützen den onReject-Callback für die Behandlung blockierter Ausführungen.

Beispiel

ts
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // Called after each successful execution
    console.log('Async function executed', rateLimiter.store.state.successCount)
  },
  onReject: (rateLimiter) => {
    // Called when an execution is rejected
    console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`)
  },
  onError: (error) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
  }
})
const asyncLimiter = new AsyncRateLimiter(async (id) => {
  await saveToAPI(id)
}, {
  limit: 5,
  window: 1000,
  onExecute: (rateLimiter) => {
    // Called after each successful execution
    console.log('Async function executed', rateLimiter.store.state.successCount)
  },
  onReject: (rateLimiter) => {
    // Called when an execution is rejected
    console.log(`Rate limit exceeded. Try again in ${rateLimiter.getMsUntilNextWindow()}ms`)
  },
  onError: (error) => {
    // Called if the async function throws an error
    console.error('Async function failed:', error)
  }
})

4. Sequenzielle Ausführung

Da die Methode maybeExecute des Ratenbegrenzers ein Promise zurückgibt, können Sie wählen, auf jede Ausführung zu warten, bevor Sie die nächste starten. Dies gibt Ihnen die Kontrolle über die Ausführungsreihenfolge und stellt sicher, dass jeder Aufruf die aktuellsten Daten verarbeitet. Dies ist besonders nützlich, wenn Sie mit Vorgängen zu tun haben, die von den Ergebnissen früherer Aufrufe abhängen oder wenn die Aufrechterhaltung der Datenkonsistenz entscheidend ist.

Wenn Sie beispielsweise das Profil eines Benutzers aktualisieren und dann sofort dessen aktualisierte Daten abrufen, können Sie die Aktualisierungsoperation awaiten, bevor Sie den Abruf starten.

Dynamische Optionen und Aktivierung/Deaktivierung

Genau wie der synchrone Ratenbegrenzer unterstützt der asynchrone Ratenbegrenzer dynamische Optionen für limit, window und enabled, die Funktionen sein können, die die Ratenbegrenzer-Instanz empfangen. Dies ermöglicht ein ausgeklügeltes, laufzeitadaptives Ratenbegrenzungsverhalten.

Zustandsverwaltung

Die Klasse AsyncRateLimiter verwendet TanStack Store für reaktives Zustandsmanagement und bietet Echtzeit-Zugriff auf den Ausführungsstatus, die Fehlerverfolgung und Ablehnungsstatistiken. Alle Zustände werden in einem TanStack Store gespeichert und können über asyncLimiter.store.state abgerufen werden. Wenn Sie jedoch einen Framework-Adapter wie React oder Solid verwenden, möchten Sie den Zustand nicht von hier lesen. Stattdessen lesen Sie den Zustand von asyncLimiter.state und stellen einen Selector-Callback als 3. Argument für den Hook useAsyncRateLimiter bereit, um sich für die Zustandsverfolgung zu entscheiden, wie unten gezeigt.

Zustandsselektor (Framework-Adapter)

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 rateLimiter.state leer ({}), da der Selector standardmäßig leer ist. Hier werden reaktive Zustände von einem TanStack Store useStore gespeichert. Sie müssen sich für die Zustandsverfolgung entscheiden, indem Sie eine Selector-Funktion bereitstellen.

ts
// Default behavior - no reactive state subscriptions
const asyncLimiter = useAsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })
console.log(asyncLimiter.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncLimiter = useAsyncRateLimiter(
  asyncFn, 
  { limit: 5, window: 1000 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncLimiter.state.isExecuting) // Reactive value

// Multiple state properties
const asyncLimiter = useAsyncRateLimiter(
  asyncFn,
  { limit: 5, window: 1000 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)
// Default behavior - no reactive state subscriptions
const asyncLimiter = useAsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })
console.log(asyncLimiter.state) // {}

// Opt-in to re-render when isExecuting changes
const asyncLimiter = useAsyncRateLimiter(
  asyncFn, 
  { limit: 5, window: 1000 },
  (state) => ({ isExecuting: state.isExecuting })
)
console.log(asyncLimiter.state.isExecuting) // Reactive value

// Multiple state properties
const asyncLimiter = useAsyncRateLimiter(
  asyncFn,
  { limit: 5, window: 1000 },
  (state) => ({
    isExecuting: state.isExecuting,
    successCount: state.successCount,
    errorCount: state.errorCount
  })
)

Anfangszustand

Sie können Anfangswerte für den Zustand beim Erstellen eines asynchronen Ratenbegrenzers angeben

ts
const savedState = localStorage.getItem('async-rate-limiter-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncLimiter = new AsyncRateLimiter(asyncFn, {
  limit: 5,
  window: 1000,
  initialState
})
const savedState = localStorage.getItem('async-rate-limiter-state')
const initialState = savedState ? JSON.parse(savedState) : {}

const asyncLimiter = new AsyncRateLimiter(asyncFn, {
  limit: 5,
  window: 1000,
  initialState
})

Zustandsänderungen abonnieren

Der Store ist reaktiv und unterstützt Abonnements

ts
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// Subscribe to state changes
const unsubscribe = asyncLimiter.store.subscribe((state) => {
  // do something with the state like persist it to localStorage
})

// Unsubscribe when done
unsubscribe()
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// Subscribe to state changes
const unsubscribe = asyncLimiter.store.subscribe((state) => {
  // do something with the state like persist it to localStorage
})

// Unsubscribe when done
unsubscribe()

Hinweis: Dies ist nicht erforderlich, wenn Sie einen Framework-Adapter verwenden, da der zugrunde liegende Hook useStore dies bereits tut. Sie können useStore auch aus TanStack Store importieren und verwenden, um rateLimiter.store.state bei Bedarf in reaktive Zustände mit einem benutzerdefinierten Selector umzuwandeln.

Verfügbare Zustandseigenschaften

Die AsyncRateLimiterState enthält

  • errorCount: Anzahl der Funktionsausführungen, die zu Fehlern geführt haben
  • executionTimes: Array von Zeit­stempeln, wann Ausführungen für Raten­begrenzungs­berechnungen stattfanden
  • isExecuting: Ob die ratenbegrenzte Funktion derzeit asynchron ausgeführt wird
  • lastResult: Das Ergebnis der letzten erfolgreichen Funktionsausführung
  • maybeExecuteCount: Anzahl der Aufrufe von maybeExecute
  • rejectionCount: Anzahl der Funktions­ausführungen, die aufgrund von Raten­begrenzung abgelehnt wurden
  • settledCount: Anzahl der abgeschlossenen Funktionsausführungen (entweder erfolgreich oder mit Fehlern)
  • status: Aktueller Ausführungsstatus ('disabled' | 'exceeded' | 'idle')
  • successCount: Anzahl der Funktionsausführungen, die erfolgreich abgeschlossen wurden

Hilfsmethoden

Der asynchrone Ratenbegrenzer bietet Hilfsmethoden, die Werte basierend auf dem aktuellen Zustand berechnen

ts
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// These methods use the current state to compute values
console.log(asyncLimiter.getRemainingInWindow()) // Number of calls remaining in current window
console.log(asyncLimiter.getMsUntilNextWindow()) // Milliseconds until next window
const asyncLimiter = new AsyncRateLimiter(asyncFn, { limit: 5, window: 1000 })

// These methods use the current state to compute values
console.log(asyncLimiter.getRemainingInWindow()) // Number of calls remaining in current window
console.log(asyncLimiter.getMsUntilNextWindow()) // Milliseconds until next window

Diese Methoden sind berechnete Werte, die den aktuellen Zustand verwenden und nicht über den Store abgerufen werden müssen.

Framework-Adapter

Jeder Framework-Adapter stellt Hooks bereit, die auf der Kernfunktionalität der asynchronen Ratenbegrenzung aufbauen, um sich in das Zustandsverwaltungssystem des Frameworks zu integrieren. Hooks wie createAsyncRateLimiter, useAsyncRateLimitedCallback oder ähnliche sind für jedes Framework verfügbar.


Für Kernkonzepte der Ratenbegrenzung und synchrone Ratenbegrenzung siehe den Rate Limiting Guide.

Unsere Partner
Code Rabbit
Unkey
Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.

Bytes abonnieren

Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.

Bytes

Kein Spam. Jederzeit kündbar.