Base

Debounce Plugin

Debounce event notifications for performance optimization.

The Debounce Plugin debounces event notifications from check-in and check-out operations to optimize performance in high-frequency scenarios like real-time search, rapid user interactions, or auto-save features.

Key Concept

Operations are immediate, notifications are debounced: The plugin executes check-in/check-out operations immediately and updates the registry. Only the event notifications (onCheckIn/onCheckOut hooks) are debounced.

This means your data is always up-to-date, but listeners are notified in batches to reduce processing overhead.

Installation

import { useCheckIn } from 'vue-airport';
import { createDebouncePlugin } from '@vue-airport/plugins-base';

const { createDesk } = useCheckIn<SearchResult>();
const { desk } = createDesk('search', {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 500,
      checkOutDelay: 300,
      maxWait: 2000
    })
  ]
});

Options

checkInDelay: number

Debounce delay in milliseconds for check-in notifications. Default: 300.

createDebouncePlugin({
  checkInDelay: 500 // Wait 500ms before notifying
})

checkOutDelay: number

Debounce delay in milliseconds for check-out notifications. Default: 300.

createDebouncePlugin({
  checkOutDelay: 300 // Wait 300ms before notifying
})

maxWait: number

Maximum time the notification can be delayed before it's forced to execute. Optional.

createDebouncePlugin({
  checkInDelay: 500,
  maxWait: 2000 // Force notification after 2 seconds max
})

Basic Usage

interface SearchResult {
  title: string;
  description: string;
}

const { desk } = createDesk('search', {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 500
    })
  ]
});

// Subscribe to debounced check-in events
desk.onDebouncedCheckIn((id, data) => {
  console.log('Debounced check-in:', id, data);
  // Update UI, trigger API call, etc.
});

// Rapid check-ins (e.g., search results updating)
desk.checkIn('result-1', { title: 'Vue', description: 'Framework' });
desk.checkIn('result-2', { title: 'Vue Router', description: 'Routing' });
desk.checkIn('result-3', { title: 'VueAirport', description: 'State' });

// Registry is updated immediately, but callback is called once after 500ms
// Callback receives all three items (batched)

Subscribing to Debounced Events

Check-in Events

desk.onDebouncedCheckIn((id, data) => {
  console.log('Check-in notification:', id, data.title);
  // This is called once after the debounce delay
  // with the latest data for each ID
});

Check-out Events

desk.onDebouncedCheckOut((id) => {
  console.log('Check-out notification:', id);
  // This is called once after the debounce delay
  // with all the IDs that were checked out
});

Controlling Debounce

Flush Immediately

Process all pending notifications immediately:

// Queue up some operations
desk.checkIn('item-1', { value: 1 });
desk.checkIn('item-2', { value: 2 });
desk.checkIn('item-3', { value: 3 });

// Don't wait for the delay - flush now
desk.flushDebounce();
// Debounced callbacks are called immediately

Cancel Pending

Cancel all pending notifications:

// Queue up some operations
desk.checkIn('item-1', { value: 1 });
desk.checkIn('item-2', { value: 2 });

// Changed your mind - cancel the notifications
desk.cancelDebounce();
// Debounced callbacks will NOT be called

Monitoring Pending Operations

// Check how many notifications are pending
console.log(desk.pendingCheckInsCount); // Number of pending check-ins
console.log(desk.pendingCheckOutsCount); // Number of pending check-outs
console.log(desk.hasPendingDebounce); // true if any pending

// Use in UI
const isPending = computed(() => desk.hasPendingDebounce);

Component Integration

<script setup lang="ts">
import { useCheckIn, createDebouncePlugin } from 'vue-airport';

interface SearchResult {
  id: string;
  title: string;
  description: string;
}

const { desk } = createDesk(Symbol('search-results'), {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 300,
      maxWait: 1000
    })
  ]
});

const searchQuery = ref('');
const isSearching = computed(() => desk.hasPendingDebounce);

// Subscribe to debounced updates
desk.onDebouncedCheckIn((id, data) => {
  console.log('Search result added:', data.title);
  // Could trigger additional API calls, analytics, etc.
});

// Simulate rapid search results
watch(searchQuery, async (query) => {
  if (!query) {
    desk.clear();
    return;
  }
  
  // Simulate API response with multiple results
  const results = await fetchSearchResults(query);
  
  // Clear old results
  desk.clear();
  
  // Check in new results (rapid operations)
  results.forEach(result => {
    desk.checkIn(result.id, result);
  });
  
  // Registry is updated immediately
  // But debounced callback is called once after delay
});

const displayResults = computed(() => desk.items);
</script>

<template>
  <div>
    <input 
      v-model="searchQuery" 
      placeholder="Search..." 
      :class="{ searching: isSearching }"
    />
    
    <div v-if="isSearching" class="loading">
      Updating results...
    </div>
    
    <div class="results">
      <div v-for="item in displayResults" :key="item.id">
        <h3>{{ item.data.title }}</h3>
        <p>{{ item.data.description }}</p>
      </div>
    </div>
  </div>
</template>

Auto-save with Debounce

<script setup lang="ts">
interface FormData {
  title: string;
  content: string;
}

const { desk } = createDesk(Symbol('draft'), {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 1000,
      maxWait: 5000
    })
  ]
});

const formData = reactive({
  title: '',
  content: ''
});

// Auto-save on debounced update
desk.onDebouncedCheckIn(async (id, data) => {
  console.log('Auto-saving...');
  await saveDraft(data);
  console.log('Draft saved!');
});

// Update draft on every change
watch(formData, (newData) => {
  desk.checkIn('current-draft', { ...newData });
  // Saved after 1 second of inactivity, or 5 seconds max
}, { deep: true });
</script>

API Reference

Methods

onDebouncedCheckIn(callback: (id: string | number, data: T) => void): void

Subscribe to debounced check-in notifications.

onDebouncedCheckOut(callback: (id: string | number) => void): void

Subscribe to debounced check-out notifications.

flushDebounce(): void

Immediately process all pending event notifications.

cancelDebounce(): void

Cancel all pending event notifications.

Properties

pendingCheckInsCount: number

Number of pending check-in notifications.

pendingCheckOutsCount: number

Number of pending check-out notifications.

hasPendingDebounce: boolean

Boolean indicating if there are any pending notifications.

Behavior Details

Batching

Multiple operations on the same ID are batched - only the latest data is used:

desk.checkIn('item-1', { value: 1 });
desk.checkIn('item-1', { value: 2 });
desk.checkIn('item-1', { value: 3 });

// After delay, callback is called ONCE with { value: 3 }

Max Wait

When maxWait is set, notifications are forced after the maximum wait time:

const { desk } = createDesk(Symbol('items'), {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 500,
      maxWait: 2000
    })
  ]
});

// Operations every 400ms (before 500ms delay)
setInterval(() => {
  desk.checkIn('item', { time: Date.now() });
}, 400);

// Notification is forced after 2000ms even though operations continue

Use Cases

Real-time Search

Debounce search result updates to avoid excessive rendering:

const { desk } = createDesk(Symbol('search'), {
  plugins: [createDebouncePlugin({ checkInDelay: 300 })]
});

// User types rapidly, results update in batches

Auto-save

Debounce save operations while editing:

const { desk } = createDesk(Symbol('document'), {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 1000,
      maxWait: 5000
    })
  ]
});

// Save after 1s of inactivity, or 5s max

Live Updates

Debounce notifications for live data feeds:

const { desk } = createDesk(Symbol('live-data'), {
  plugins: [
    createDebouncePlugin({
      checkInDelay: 200,
      maxWait: 1000
    })
  ]
});

// Batch rapid updates, ensure UI updates at least every second

Form Validation

Debounce validation checks:

const { desk } = createDesk(Symbol('form-fields'), {
  plugins: [createDebouncePlugin({ checkInDelay: 500 })]
});

desk.onDebouncedCheckIn((id, data) => {
  validateField(id, data);
});

Performance Impact

Performance benefits: The Debounce Plugin can significantly reduce the number of expensive operations (API calls, UI updates, validations) in high-frequency scenarios, leading to better performance and user experience.

Before Debounce

// 100 operations = 100 API calls
for (let i = 0; i < 100; i++) {
  desk.checkIn(`item-${i}`, { value: i });
  // Each triggers an API call
}

With Debounce

// 100 operations = 1 batched API call
for (let i = 0; i < 100; i++) {
  desk.checkIn(`item-${i}`, { value: i });
}

desk.onDebouncedCheckIn(() => {
  // Called once after delay with all items
  batchedApiCall(desk.items);
});