asyncBatchAsyncBatcher KlasseAlle Kernkonzepte aus dem Batching Guide gelten auch für asynchrones Batching.
Während der synchrone Batcher für viele Anwendungsfälle gut funktioniert, bietet asynchrones Batching zusätzliche Funktionen, die besonders nützlich sind, wenn
TanStack Pacer bietet asynchrones Batching über die Klasse AsyncBatcher und die Funktion asyncBatch. Im Gegensatz zur synchronen Version verarbeitet der asynchrone Batcher Promises und bietet robuste Fehlerbehandlungsfunktionen.
Die Funktion asyncBatch bietet eine einfache Möglichkeit, eine asynchrone Batching-Funktion zu erstellen.
import { asyncBatch } from '@tanstack/pacer'
const processAsyncBatch = asyncBatch<number>(
async (items) => {
// Process the batch asynchronously
const results = await Promise.all(
items.map(item => processApiCall(item))
)
return results
},
{
maxSize: 3,
wait: 2000,
onSuccess: (results, batch, batcher) => {
console.log('Batch completed successfully:', results)
console.log('Processed batch:', batch)
console.log('Total successes:', batcher.store.state.successCount)
},
onError: (error, batch, batcher) => {
console.error('Batch failed:', error)
console.log('Failed batch:', batch)
console.log('Total errors:', batcher.store.state.errorCount)
}
}
)
// Add items to be batched
processAsyncBatch(1)
processAsyncBatch(2)
processAsyncBatch(3) // Triggers batch processing
import { asyncBatch } from '@tanstack/pacer'
const processAsyncBatch = asyncBatch<number>(
async (items) => {
// Process the batch asynchronously
const results = await Promise.all(
items.map(item => processApiCall(item))
)
return results
},
{
maxSize: 3,
wait: 2000,
onSuccess: (results, batch, batcher) => {
console.log('Batch completed successfully:', results)
console.log('Processed batch:', batch)
console.log('Total successes:', batcher.store.state.successCount)
},
onError: (error, batch, batcher) => {
console.error('Batch failed:', error)
console.log('Failed batch:', batch)
console.log('Total errors:', batcher.store.state.errorCount)
}
}
)
// Add items to be batched
processAsyncBatch(1)
processAsyncBatch(2)
processAsyncBatch(3) // Triggers batch processing
Hinweis: Bei der Verwendung von React bevorzugen Sie den Hook useAsyncBatchedCallback gegenüber der Funktion asyncBatch für eine bessere Integration mit dem Lebenszyklus von React und die automatische Bereinigung.
Für mehr Kontrolle über das asynchrone Batch-Verhalten verwenden Sie die Klasse AsyncBatcher direkt.
import { AsyncBatcher } from '@tanstack/pacer'
const batcher = new AsyncBatcher<number>(
async (items) => {
// Process the batch asynchronously
const results = await Promise.all(
items.map(item => processApiCall(item))
)
return results
},
{
maxSize: 5,
wait: 3000,
onSuccess: (results, batch, batcher) => {
console.log('Batch succeeded:', results)
console.log('Processed batch:', batch)
},
onError: (error, batch, batcher) => {
console.error('Batch failed:', error)
console.log('Failed batch:', batch)
}
}
)
// Access current state via TanStack Store
console.log(batcher.store.state.successCount) // Number of successful batch executions
console.log(batcher.store.state.errorCount) // Number of failed batch executions
console.log(batcher.store.state.isExecuting) // Whether a batch is currently executing
console.log(batcher.store.state.lastResult) // Result from most recent batch
// Add items to the batch
batcher.addItem(1)
batcher.addItem(2)
// Control batch execution
batcher.stop() // Stop processing
batcher.start() // Resume processing
import { AsyncBatcher } from '@tanstack/pacer'
const batcher = new AsyncBatcher<number>(
async (items) => {
// Process the batch asynchronously
const results = await Promise.all(
items.map(item => processApiCall(item))
)
return results
},
{
maxSize: 5,
wait: 3000,
onSuccess: (results, batch, batcher) => {
console.log('Batch succeeded:', results)
console.log('Processed batch:', batch)
},
onError: (error, batch, batcher) => {
console.error('Batch failed:', error)
console.log('Failed batch:', batch)
}
}
)
// Access current state via TanStack Store
console.log(batcher.store.state.successCount) // Number of successful batch executions
console.log(batcher.store.state.errorCount) // Number of failed batch executions
console.log(batcher.store.state.isExecuting) // Whether a batch is currently executing
console.log(batcher.store.state.lastResult) // Result from most recent batch
// Add items to the batch
batcher.addItem(1)
batcher.addItem(2)
// Control batch execution
batcher.stop() // Stop processing
batcher.start() // Resume processing
Im Gegensatz zum synchronen Batcher, der void zurückgibt, ermöglicht die asynchrone Version, den Rückgabewert Ihrer Batch-Funktion zu erfassen und zu verwenden.
const batcher = new AsyncBatcher<string>(
async (items) => {
const results = await processBatch(items)
return results
},
{
maxSize: 5,
onSuccess: (results, batch, batcher) => {
// Handle the returned results
console.log('Batch results:', results)
console.log('Processed batch:', batch)
}
}
)
const batcher = new AsyncBatcher<string>(
async (items) => {
const results = await processBatch(items)
return results
},
{
maxSize: 5,
onSuccess: (results, batch, batcher) => {
// Handle the returned results
console.log('Batch results:', results)
console.log('Processed batch:', batch)
}
}
)
Der asynchrone Batcher bietet umfassende Fehlerbehandlungsfunktionen.
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might throw an error
const results = await riskyBatchOperation(items)
return results
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
// Handle batch errors
console.error('Batch processing failed:', error)
console.log('Items that failed:', batch)
console.log('Total error count:', batcher.store.state.errorCount)
},
throwOnError: false, // Don't throw errors, just handle them
onSuccess: (results, batch, batcher) => {
console.log('Batch succeeded:', results)
console.log('Processed batch:', batch)
console.log('Total success count:', batcher.store.state.successCount)
},
onSettled: (batch, batcher) => {
// Called after every batch (success or failure)
console.log('Batch settled:', batch)
console.log('Total batches:', batcher.store.state.settleCount)
}
}
)
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might throw an error
const results = await riskyBatchOperation(items)
return results
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
// Handle batch errors
console.error('Batch processing failed:', error)
console.log('Items that failed:', batch)
console.log('Total error count:', batcher.store.state.errorCount)
},
throwOnError: false, // Don't throw errors, just handle them
onSuccess: (results, batch, batcher) => {
console.log('Batch succeeded:', results)
console.log('Processed batch:', batch)
console.log('Total success count:', batcher.store.state.successCount)
},
onSettled: (batch, batcher) => {
// Called after every batch (success or failure)
console.log('Batch settled:', batch)
console.log('Total batches:', batcher.store.state.settleCount)
}
}
)
Der asynchrone Batcher verfolgt, wann Batches aktiv ausgeführt werden.
const batcher = new AsyncBatcher<number>(
async (items) => {
console.log('Starting batch execution...')
const results = await longRunningBatchOperation(items)
console.log('Batch execution completed')
return results
},
{
maxSize: 5,
onItemsChange: (batcher) => {
console.log('Is executing:', batcher.store.state.isExecuting)
console.log('Items in queue:', batcher.store.state.size)
}
}
)
const batcher = new AsyncBatcher<number>(
async (items) => {
console.log('Starting batch execution...')
const results = await longRunningBatchOperation(items)
console.log('Batch execution completed')
return results
},
{
maxSize: 5,
onItemsChange: (batcher) => {
console.log('Is executing:', batcher.store.state.isExecuting)
console.log('Items in queue:', batcher.store.state.size)
}
}
)
Der AsyncBatcher unterstützt diese asynchronen Rückrufe:
Der asynchrone Batcher bietet flexible Fehlerbehandlung durch die Option throwOnError.
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might throw an error
throw new Error('Batch processing failed')
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
console.error('Handling error:', error)
},
throwOnError: true, // Will throw errors even with onError handler
// throwOnError: false, // Will swallow errors (default if onError is provided)
// throwOnError: undefined, // Uses default behavior based on onError presence
}
)
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might throw an error
throw new Error('Batch processing failed')
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
console.error('Handling error:', error)
},
throwOnError: true, // Will throw errors even with onError handler
// throwOnError: false, // Will swallow errors (default if onError is provided)
// throwOnError: undefined, // Uses default behavior based on onError presence
}
)
Wie der synchrone Batcher unterstützt der asynchrone Batcher dynamische Optionen.
const batcher = new AsyncBatcher<number>(
async (items) => {
return await processBatch(items)
},
{
// Dynamic batch size based on success rate
maxSize: (batcher) => {
const successRate = batcher.store.state.successCount / Math.max(1, batcher.store.state.settleCount)
return successRate > 0.8 ? 10 : 5 // Larger batches if success rate is high
},
// Dynamic wait time based on error count
wait: (batcher) => {
return batcher.store.state.errorCount > 5 ? 5000 : 2000 // Wait longer if errors are frequent
}
}
)
const batcher = new AsyncBatcher<number>(
async (items) => {
return await processBatch(items)
},
{
// Dynamic batch size based on success rate
maxSize: (batcher) => {
const successRate = batcher.store.state.successCount / Math.max(1, batcher.store.state.settleCount)
return successRate > 0.8 ? 10 : 5 // Larger batches if success rate is high
},
// Dynamic wait time based on error count
wait: (batcher) => {
return batcher.store.state.errorCount > 5 ? 5000 : 2000 // Wait longer if errors are frequent
}
}
)
Der asynchrone Batcher unterstützt das Leeren ausstehender Batches, um die Verarbeitung sofort auszulösen.
const batcher = new AsyncBatcher(asyncBatchFn, { maxSize: 10, wait: 5000 })
batcher.addItem('item1')
batcher.addItem('item2')
console.log(batcher.store.state.isPending) // true
// Flush immediately instead of waiting
const result = await batcher.flush()
console.log('Flush result:', result)
console.log(batcher.store.state.isEmpty) // true (batch was processed)
const batcher = new AsyncBatcher(asyncBatchFn, { maxSize: 10, wait: 5000 })
batcher.addItem('item1')
batcher.addItem('item2')
console.log(batcher.store.state.isPending) // true
// Flush immediately instead of waiting
const result = await batcher.flush()
console.log('Flush result:', result)
console.log(batcher.store.state.isEmpty) // true (batch was processed)
Die Klasse AsyncBatcher verwendet TanStack Store für reaktives Zustandsmanagement und bietet Echtzeit-Zugriff auf den Batch-Ausführungsstatus, die Fehlerverfolgung und die Verarbeitungsstatistiken. Alle Zustandsinformationen werden in einem TanStack Store gespeichert und können über asyncBatcher.store.state abgerufen werden. Wenn Sie jedoch einen Framework-Adapter wie React oder Solid verwenden, sollten Sie den Zustand nicht von hier lesen. Stattdessen lesen Sie den Zustand von asyncBatcher.state und stellen eine Selektor-Callback als drittes Argument für den Hook useAsyncBatcher bereit, um sich für die Zustandsverfolgung zu opt-in, 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 asyncBatcher.state leer ({}), da der Selektor standardmäßig leer ist. Hier werden reaktive Zustände aus einem TanStack Store useStore gespeichert. Sie müssen sich für die Zustandsverfolgung entscheiden, indem Sie eine Selektor-Funktion bereitstellen.
// Default behavior - no reactive state subscriptions
const batcher = useAsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
console.log(batcher.state) // {}
// Opt-in to re-render when isExecuting changes
const batcher = useAsyncBatcher(
asyncBatchFn,
{ maxSize: 5, wait: 1000 },
(state) => ({ isExecuting: state.isExecuting })
)
console.log(batcher.state.isExecuting) // Reactive value
// Multiple state properties
const batcher = useAsyncBatcher(
asyncBatchFn,
{ maxSize: 5, wait: 1000 },
(state) => ({
isExecuting: state.isExecuting,
successCount: state.successCount,
errorCount: state.errorCount
})
)
// Default behavior - no reactive state subscriptions
const batcher = useAsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
console.log(batcher.state) // {}
// Opt-in to re-render when isExecuting changes
const batcher = useAsyncBatcher(
asyncBatchFn,
{ maxSize: 5, wait: 1000 },
(state) => ({ isExecuting: state.isExecuting })
)
console.log(batcher.state.isExecuting) // Reactive value
// Multiple state properties
const batcher = useAsyncBatcher(
asyncBatchFn,
{ maxSize: 5, wait: 1000 },
(state) => ({
isExecuting: state.isExecuting,
successCount: state.successCount,
errorCount: state.errorCount
})
)
Sie können initiale Zustandswerte beim Erstellen eines asynchronen Batchers angeben. Dies wird häufig verwendet, um Zustände aus persistentem Speicher wiederherzustellen.
// Load initial state from localStorage
const savedState = localStorage.getItem('async-batcher-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const batcher = new AsyncBatcher(asyncBatchFn, {
maxSize: 5,
wait: 1000,
initialState
})
// Load initial state from localStorage
const savedState = localStorage.getItem('async-batcher-state')
const initialState = savedState ? JSON.parse(savedState) : {}
const batcher = new AsyncBatcher(asyncBatchFn, {
maxSize: 5,
wait: 1000,
initialState
})
Der Store ist reaktiv und unterstützt Abonnements
const batcher = new AsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
// Subscribe to state changes
const unsubscribe = batcher.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
const batcher = new AsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
// Subscribe to state changes
const unsubscribe = batcher.store.subscribe((state) => {
// do something with the state like persist it to localStorage
})
// Unsubscribe when done
unsubscribe()
Hinweis: Dies ist nicht notwendig, wenn Sie einen Framework-Adapter verwenden, da der zugrunde liegende Hook useStore dies bereits erledigt. Sie können auch useStore von TanStack Store importieren und verwenden, um batcher.store.state nach Bedarf in reaktiven Zustand mit einem benutzerdefinierten Selektor umzuwandeln.
const batcher = useAsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
// you could manually use the `useStore` hook to subscribe to state changes in whatever scope you want
const state = useStore(batcher.store, (state) => ({
successCount: state.successCount,
}))
console.log(state)
const batcher = useAsyncBatcher(asyncBatchFn, { maxSize: 5, wait: 1000 })
// you could manually use the `useStore` hook to subscribe to state changes in whatever scope you want
const state = useStore(batcher.store, (state) => ({
successCount: state.successCount,
}))
console.log(state)
Die AsyncBatcherState beinhaltet:
Der asynchrone Batcher verfolgt Elemente, die während der Batch-Verarbeitung fehlgeschlagen sind.
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might fail for some items
if (items.some(item => item < 0)) {
throw new Error('Negative numbers not allowed')
}
return await processBatch(items)
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
console.log('Failed batch:', batch)
console.log('All failed items:', batcher.peekFailedItems())
}
}
)
const batcher = new AsyncBatcher<number>(
async (items) => {
// This might fail for some items
if (items.some(item => item < 0)) {
throw new Error('Negative numbers not allowed')
}
return await processBatch(items)
},
{
maxSize: 3,
onError: (error, batch, batcher) => {
console.log('Failed batch:', batch)
console.log('All failed items:', batcher.peekFailedItems())
}
}
)
Jeder Framework-Adapter bietet Hooks, die auf der Kernfunktionalität für asynchrones Batching aufbauen, um sich in das Zustandsmanagementsystem des Frameworks zu integrieren. Hooks wie useAsyncBatcher oder ähnliche sind für jedes Framework verfügbar.
Für Kernkonzepte des Batchings und synchrones Batching siehe den Batching Guide.
Ihre wöchentliche Dosis JavaScript-Nachrichten. Jeden Montag kostenlos an über 100.000 Entwickler geliefert.