<script lang="ts">
import { TanStackDevtools } from '@tanstack/svelte-devtools'
import { pacerDevtoolsPlugin } from '@tanstack/svelte-pacer-devtools'
import { createAsyncBatcher } from '@tanstack/svelte-pacer/async-batcher'
const fakeProcessingTime = 1000
type Item = {
id: number
value: string
timestamp: number
}
let processedBatches = $state<
Array<{
items: Array<Item>
result: string
timestamp: number
}>
>([])
let errors = $state<Array<string>>([])
async function processBatch(items: Array<Item>): Promise<string> {
console.log('Processing batch of', items.length, 'items:', items)
await new Promise((resolve) => setTimeout(resolve, fakeProcessingTime))
const result = `Processed ${items.length} items: ${items.map((item) => item.value).join(', ')}`
processedBatches = [
...processedBatches,
{ items, result, timestamp: Date.now() },
]
return result
}
const asyncBatcher = createAsyncBatcher(processBatch, () => ({
key: 'createAsyncBatcher',
maxSize: 5,
wait: 4000,
getShouldExecute: (items) =>
items.some((item) => item.value.includes('urgent')),
throwOnError: false,
onSuccess: (result, batch, batcher) => {
console.log('Batch succeeded:', result)
console.log('Processed batch:', batch)
console.log('Total successful batches:', batcher.store.state.successCount)
},
onError: (error: any, _batcher) => {
console.error('Batch failed:', error)
errors = [
...errors,
`Error: ${error} (${new Date().toLocaleTimeString()})`,
]
},
onSettled: (batch, batcher) => {
console.log('Batch settled:', batch)
console.log(
'Total processed items:',
batcher.store.state.totalItemsProcessed,
)
},
}))
const addItem = (isUrgent = false) => {
const nextId = Date.now()
const item: Item = {
id: nextId,
value: isUrgent ? `urgent-${nextId}` : `item-${nextId}`,
timestamp: nextId,
}
asyncBatcher.addItem(item)
}
const executeCurrentBatch = async () => {
try {
const result = await asyncBatcher.flush()
console.log('Manual execution result:', result)
} catch (error) {
console.error('Manual execution failed:', error)
}
}
</script>
<div>
<h1>TanStack Pacer createAsyncBatcher Example</h1>
<asyncBatcher.Subscribe
selector={(state) => ({
size: state.size,
isExecuting: state.isExecuting,
status: state.status,
successCount: state.successCount,
errorCount: state.errorCount,
totalItemsProcessed: state.totalItemsProcessed,
})}
>{#snippet children({
size,
isExecuting,
status,
successCount,
errorCount,
totalItemsProcessed,
})}<div>
<h3>Batch Status</h3>
<div>Current Batch Size: {size}</div>
<div>Max Batch Size: 5</div>
<div>Is Executing: {isExecuting ? 'Yes' : 'No'}</div>
<div>Status: {status}</div>
<div>Successful Batches: {successCount}</div>
<div>Failed Batches: {errorCount}</div>
<div>Total Items Processed: {totalItemsProcessed}</div>
</div>{/snippet}</asyncBatcher.Subscribe
><asyncBatcher.Subscribe selector={(state) => ({ items: state.items })}
>{#snippet children({ items })}<div>
<h3>Current Batch Items</h3>
<div style="min-height: 100px">
{#if items.length === 0}<em>No items in current batch</em
>{:else}{#each items as item, index (index)}<div>
{index + 1}: {item.value} (added at{' '}{new Date(
item.timestamp,
).toLocaleTimeString()})
</div>{/each}{/if}
</div>
</div>{/snippet}</asyncBatcher.Subscribe
>
<div>
<h3>Controls</h3>
<div
style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; max-width: 600px"
>
<button onclick={() => addItem(false)}>Add Regular Item</button><button
onclick={() => addItem(true)}
>
Add Urgent Item (Processes Immediately)</button
><asyncBatcher.Subscribe
selector={(state) => ({
size: state.size,
isExecuting: state.isExecuting,
})}
>{#snippet children({ size, isExecuting })}<button
disabled={size === 0 || isExecuting}
onclick={executeCurrentBatch}
>
Process Current Batch Now</button
><button
onclick={() => asyncBatcher.clear()}
disabled={size === 0 || isExecuting}
>
Clear Current Batch
</button>{/snippet}</asyncBatcher.Subscribe
>
</div>
</div>
<div>
<h3>Processed Batches ({processedBatches.length})</h3>
<div>
{#if processedBatches.length === 0}<em>No batches processed yet</em
>{:else}{#each processedBatches as batch, index (index)}<div>
<strong>Batch {index + 1}</strong> (processed at{' '}{new Date(
batch.timestamp,
).toLocaleTimeString()})
<div>{batch.result}</div>
</div>{/each}{/if}
</div>
</div>
{#if errors.length > 0}<div>
<h3>Errors ({errors.length})</h3>
<div>
{#each errors as error, index (index)}<div>{error}</div>{/each}
</div>
<button onclick={() => (errors = [])}>Clear Errors</button>
</div>{/if}<asyncBatcher.Subscribe selector={(state) => state}
>{#snippet children(state)}<pre style="margin-top: 20px">{JSON.stringify(
state,
null,
2,
)}</pre>{/snippet}</asyncBatcher.Subscribe
>
</div>
{#if import.meta.env.DEV}<TanStackDevtools
plugins={[pacerDevtoolsPlugin()]}
/>{/if}