Documentation
Framework
Version
Debouncer API Reference
Throttler API Reference
Rate Limiter API Reference
Queue API Reference
Batcher API Reference

Solid Example: CreateAsyncQueuer

tsx
import { For, createSignal } from 'solid-js'
import { render } from 'solid-js/web'
import { createAsyncQueuer } from '@tanstack/solid-pacer/async-queuer'

const fakeWaitTime = 500

type Item = number

function App() {
  // Use your state management library of choice
  const [concurrency, setConcurrency] = createSignal(2)

  // The function to process each item (now a number)
  async function processItem(item: Item): Promise<void> {
    await new Promise((resolve) => setTimeout(resolve, fakeWaitTime))
    console.log(`Processed ${item}`)
  }

  const queuer = createAsyncQueuer(
    processItem,
    {
      maxSize: 25,
      initialItems: Array.from({ length: 10 }, (_, i) => i + 1),
      concurrency: () => concurrency(), // Process 2 items concurrently
      started: false,
      wait: 100, // for demo purposes - usually you would not want extra wait time if you are also throttling with concurrency
      onReject: (item, queuer) => {
        console.log(
          'Queue is full, rejecting item',
          item,
          queuer.store.state.rejectionCount,
        )
      },
      onError: (error, _item, queuer) => {
        console.error(
          'Error processing item',
          error,
          queuer.store.state.errorCount,
        ) // optionally, handle errors here instead of your own try/catch
      },
    },
    // Alternative to queuer.Subscribe: pass a selector as 3rd arg to track state and subscribe to updates
    // (state) => state,
  )

  return (
    <div>
      <h1>TanStack Pacer createAsyncQueuer Example</h1>
      <queuer.Subscribe
        selector={(state) => ({
          size: state.size,
          status: state.status,
          successCount: state.successCount,
          items: state.items,
          isFull: state.isFull,
          isEmpty: state.isEmpty,
          isIdle: state.isIdle,
          rejectionCount: state.rejectionCount,
          activeItems: state.activeItems,
          isRunning: state.isRunning,
        })}
      >
        {(state) => (
          <>
            <div>Queue Size: {state().size}</div>
            <div>Queue Max Size: {25}</div>
            <div>Queue Full: {state().isFull ? 'Yes' : 'No'}</div>
            <div>Queue Empty: {state().isEmpty ? 'Yes' : 'No'}</div>
            <div>Queue Idle: {state().isIdle ? 'Yes' : 'No'}</div>
            <div>Queuer Status: {state().status}</div>
            <div>Items Processed: {state().successCount}</div>
            <div>Items Rejected: {state().rejectionCount}</div>
            <div>Active Tasks: {state().activeItems.length}</div>
            <div>Pending Tasks: {state().items.length}</div>
            <div>
              Concurrency:{' '}
              <input
                type="number"
                min={1}
                value={concurrency()}
                onInput={(e) =>
                  setConcurrency(
                    Math.max(1, parseInt(e.currentTarget.value) || 1),
                  )
                }
                style={{ width: '60px' }}
              />
            </div>
            <div style={{ 'min-height': '250px' }}>
              Queue Items:
              <For each={state().items}>
                {(item, index) => (
                  <div>
                    {index()}: {item}
                  </div>
                )}
              </For>
            </div>
            <div
              style={{
                display: 'grid',
                'grid-template-columns': 'repeat(2, 1fr)',
                gap: '8px',
                'max-width': '600px',
                margin: '16px 0',
              }}
            >
              <button
                onClick={() => {
                  const nextNumber = state().items.length
                    ? Math.max(...state().items) + 1
                    : 1
                  queuer.addItem(nextNumber)
                }}
                disabled={state().isFull}
              >
                Add Async Task
              </button>
              <button onClick={() => queuer.getNextItem()}>
                Get Next Item
              </button>
              <button onClick={() => queuer.clear()} disabled={state().isEmpty}>
                Clear Queue
              </button>
              <br />
              <button
                onClick={() => queuer.start()}
                disabled={state().isRunning}
              >
                Start Processing
              </button>
              <button
                onClick={() => queuer.stop()}
                disabled={!state().isRunning}
              >
                Stop Processing
              </button>
            </div>
          </>
        )}
      </queuer.Subscribe>
      <queuer.Subscribe selector={(state) => state}>
        {(state) => (
          <pre style={{ 'margin-top': '20px' }}>
            {JSON.stringify(state(), null, 2)}
          </pre>
        )}
      </queuer.Subscribe>
    </div>
  )
}

render(() => <App />, document.getElementById('root')!)
import { For, createSignal } from 'solid-js'
import { render } from 'solid-js/web'
import { createAsyncQueuer } from '@tanstack/solid-pacer/async-queuer'

const fakeWaitTime = 500

type Item = number

function App() {
  // Use your state management library of choice
  const [concurrency, setConcurrency] = createSignal(2)

  // The function to process each item (now a number)
  async function processItem(item: Item): Promise<void> {
    await new Promise((resolve) => setTimeout(resolve, fakeWaitTime))
    console.log(`Processed ${item}`)
  }

  const queuer = createAsyncQueuer(
    processItem,
    {
      maxSize: 25,
      initialItems: Array.from({ length: 10 }, (_, i) => i + 1),
      concurrency: () => concurrency(), // Process 2 items concurrently
      started: false,
      wait: 100, // for demo purposes - usually you would not want extra wait time if you are also throttling with concurrency
      onReject: (item, queuer) => {
        console.log(
          'Queue is full, rejecting item',
          item,
          queuer.store.state.rejectionCount,
        )
      },
      onError: (error, _item, queuer) => {
        console.error(
          'Error processing item',
          error,
          queuer.store.state.errorCount,
        ) // optionally, handle errors here instead of your own try/catch
      },
    },
    // Alternative to queuer.Subscribe: pass a selector as 3rd arg to track state and subscribe to updates
    // (state) => state,
  )

  return (
    <div>
      <h1>TanStack Pacer createAsyncQueuer Example</h1>
      <queuer.Subscribe
        selector={(state) => ({
          size: state.size,
          status: state.status,
          successCount: state.successCount,
          items: state.items,
          isFull: state.isFull,
          isEmpty: state.isEmpty,
          isIdle: state.isIdle,
          rejectionCount: state.rejectionCount,
          activeItems: state.activeItems,
          isRunning: state.isRunning,
        })}
      >
        {(state) => (
          <>
            <div>Queue Size: {state().size}</div>
            <div>Queue Max Size: {25}</div>
            <div>Queue Full: {state().isFull ? 'Yes' : 'No'}</div>
            <div>Queue Empty: {state().isEmpty ? 'Yes' : 'No'}</div>
            <div>Queue Idle: {state().isIdle ? 'Yes' : 'No'}</div>
            <div>Queuer Status: {state().status}</div>
            <div>Items Processed: {state().successCount}</div>
            <div>Items Rejected: {state().rejectionCount}</div>
            <div>Active Tasks: {state().activeItems.length}</div>
            <div>Pending Tasks: {state().items.length}</div>
            <div>
              Concurrency:{' '}
              <input
                type="number"
                min={1}
                value={concurrency()}
                onInput={(e) =>
                  setConcurrency(
                    Math.max(1, parseInt(e.currentTarget.value) || 1),
                  )
                }
                style={{ width: '60px' }}
              />
            </div>
            <div style={{ 'min-height': '250px' }}>
              Queue Items:
              <For each={state().items}>
                {(item, index) => (
                  <div>
                    {index()}: {item}
                  </div>
                )}
              </For>
            </div>
            <div
              style={{
                display: 'grid',
                'grid-template-columns': 'repeat(2, 1fr)',
                gap: '8px',
                'max-width': '600px',
                margin: '16px 0',
              }}
            >
              <button
                onClick={() => {
                  const nextNumber = state().items.length
                    ? Math.max(...state().items) + 1
                    : 1
                  queuer.addItem(nextNumber)
                }}
                disabled={state().isFull}
              >
                Add Async Task
              </button>
              <button onClick={() => queuer.getNextItem()}>
                Get Next Item
              </button>
              <button onClick={() => queuer.clear()} disabled={state().isEmpty}>
                Clear Queue
              </button>
              <br />
              <button
                onClick={() => queuer.start()}
                disabled={state().isRunning}
              >
                Start Processing
              </button>
              <button
                onClick={() => queuer.stop()}
                disabled={!state().isRunning}
              >
                Stop Processing
              </button>
            </div>
          </>
        )}
      </queuer.Subscribe>
      <queuer.Subscribe selector={(state) => state}>
        {(state) => (
          <pre style={{ 'margin-top': '20px' }}>
            {JSON.stringify(state(), null, 2)}
          </pre>
        )}
      </queuer.Subscribe>
    </div>
  )
}

render(() => <App />, document.getElementById('root')!)