Now.js Framework Documentation

Now.js Framework Documentation

SyncManager

TH 15 Dec 2025 08:52

SyncManager

ภาพรวม

SyncManager คือระบบ synchronization สำหรับ offline data ใน Now.js Framework รองรับ queue, priorities และ automatic retry

ใช้เมื่อ:

  • ต้องการ offline-first application
  • ต้องการ queue pending operations
  • ต้องการ sync data เมื่อกลับ online
  • ต้องการ priority-based sync

ทำไมต้องใช้:

  • ✅ Offline queue management
  • ✅ Priority-based synchronization
  • ✅ Automatic retry with backoff
  • ✅ Network status monitoring
  • ✅ Integration with ApiService
  • ✅ Event-based system
  • ✅ Enable/disable functionality

การใช้งานพื้นฐาน

Initialization

await SyncManager.init({
  enabled: true,
  autoSync: true,
  syncInterval: 60000, // 1 minute
  endpoints: {
    users: '/api/users',
    orders: '/api/orders',
    products: '/api/products'
  }
});

Add Pending Operations

// Add operation to sync later
await SyncManager.addPendingOperation({
  storeName: 'orders',
  method: 'add',
  data: {
    customer_id: 123,
    items: [...],
    total: 1500
  },
  priority: 'high'
});

// Update operation
await SyncManager.addPendingOperation({
  storeName: 'users',
  method: 'update',
  data: { id: 1, name: 'John Updated' },
  priority: 'medium'
});

// Delete operation
await SyncManager.addPendingOperation({
  storeName: 'products',
  method: 'delete',
  data: { id: 5 },
  priority: 'low'
});

Manual Sync

// Sync all pending operations
const results = await SyncManager.syncAll();
console.log('Synced:', results.successful);
console.log('Failed:', results.failed);

การตั้งค่า

await SyncManager.init({
  // Enable/disable sync
  enabled: true,

  // Auto sync settings
  autoSync: true,
  syncInterval: 60000,     // Sync interval (ms)

  // Retry settings
  retryStrategy: 'exponential', // 'exponential', 'linear', 'fixed'
  maxRetries: 5,

  // Parallel processing
  maxConcurrentRequests: 3,

  // Endpoints mapping
  endpoints: {
    users: '/api/users',
    orders: '/api/orders'
  },

  // Storage
  pendingOperationsStore: 'sync_pending_operations',

  // Callbacks
  onSyncComplete: (results) => {
    console.log('Sync completed:', results);
  },
  onSyncError: (error) => {
    console.error('Sync error:', error);
  }
});

Priority Levels

Priority Description
high Process first, critical operations
medium Normal priority (default)
low Process last, non-urgent operations
// High priority - process first
await SyncManager.addPendingOperation({
  storeName: 'payments',
  method: 'add',
  data: paymentData,
  priority: 'high'
});

// Low priority - process last
await SyncManager.addPendingOperation({
  storeName: 'analytics',
  method: 'add',
  data: analyticsData,
  priority: 'low'
});

Retry Strategies

Exponential Backoff (default)

// Retry intervals: 1s, 2s, 4s, 8s, 16s...
retryStrategy: 'exponential'

Linear Backoff

// Retry intervals: 1s, 2s, 3s, 4s, 5s...
retryStrategy: 'linear'

Fixed Interval

// Retry intervals: 5s, 5s, 5s, 5s, 5s...
retryStrategy: 'fixed'

Network Detection

SyncManager automatically detects network status:

// Listens for online/offline events
window.addEventListener('online', () => {
  // Auto-sync when back online (if enabled)
});

window.addEventListener('offline', () => {
  // Queue operations for later
});

API อ้างอิง

SyncManager.init(options)

Initialize SyncManager

Parameter Type Description
options object Configuration options

Returns: Promise<SyncManager>

SyncManager.enable()

Enable synchronization

SyncManager.enable();

SyncManager.disable()

Disable synchronization

SyncManager.disable();

SyncManager.addPendingOperation(operation)

Add operation to queue

Parameter Type Description
operation.storeName string Store/resource name
operation.method string 'add', 'update', 'delete'
operation.data object Data to sync
operation.priority string 'high', 'medium', 'low'

Returns: Promise<Object> - Created operation

SyncManager.syncAll()

Sync all pending operations

Returns: Promise<Object> - Results:

{
  successful: number,
  failed: number,
  skipped: number,
  details: [...]
}

SyncManager.getPendingOperations()

Get all pending operations

Returns: Promise<Array>

SyncManager.getPendingCount()

Get pending operations count

Returns: Promise<number>

SyncManager.getFailedOperations()

Get failed operations

Returns: Promise<Array>

SyncManager.resetFailedOperations()

Reset failed operations to pending

Returns: Promise<number> - Number of operations reset

SyncManager.clearPendingOperations()

Clear all pending operations

Returns: Promise<boolean>

SyncManager.deletePendingOperation(id)

Delete specific operation

Parameter Type Description
id number Operation ID

Returns: Promise<boolean>

SyncManager.getSyncStatus()

Get current sync status

Returns: Object:

{
  enabled: boolean,
  syncing: boolean,
  lastSyncTime: Date,
  pendingCount: number,
  failedCount: number,
  online: boolean
}

SyncManager.startAutoSync()

Start automatic synchronization

SyncManager.stopAutoSync()

Stop automatic synchronization

เหตุการณ์

Event เมื่อเกิด Detail
sync:started เริ่ม sync {count}
sync:complete Sync เสร็จ {successful, failed}
sync:error Sync error {error, operation}
sync:online กลับ online -
sync:offline ไป offline -
EventManager.on('sync:complete', (data) => {
  NotificationManager.success(`Synced ${data.successful} items`);
});

EventManager.on('sync:error', (data) => {
  console.error('Sync failed:', data.error);
});

ตัวอย่างการใช้งานจริง

Offline Form Submission

// Initialize sync
await SyncManager.init({
  enabled: true,
  autoSync: true,
  endpoints: {
    orders: '/api/orders'
  }
});

// Form submission
async function submitOrder(formData) {
  if (navigator.onLine) {
    // Online: submit directly
    try {
      await ApiService.post('/api/orders', formData);
      NotificationManager.success('Order submitted');
    } catch (error) {
      // Network error: queue for later
      await queueOrder(formData);
    }
  } else {
    // Offline: queue for later
    await queueOrder(formData);
  }
}

async function queueOrder(data) {
  await SyncManager.addPendingOperation({
    storeName: 'orders',
    method: 'add',
    data,
    priority: 'high'
  });

  // Also save locally
  await StorageManager.add('offline_orders', data);

  NotificationManager.info('Order saved. Will sync when online.');
}

Sync Status UI

<div id="sync-status">
  <span class="sync-indicator"></span>
  <span class="sync-text">ข้อมูลอัพเดทแล้ว</span>
</div>

<script>
async function updateSyncUI() {
  const status = SyncManager.getSyncStatus();
  const indicator = document.querySelector('.sync-indicator');
  const text = document.querySelector('.sync-text');

  if (status.syncing) {
    indicator.className = 'sync-indicator syncing';
    text.textContent = 'กำลัง sync...';
  } else if (status.pendingCount > 0) {
    indicator.className = 'sync-indicator pending';
    text.textContent = `${status.pendingCount} รายการรอ sync`;
  } else if (!status.online) {
    indicator.className = 'sync-indicator offline';
    text.textContent = 'Offline';
  } else {
    indicator.className = 'sync-indicator synced';
    text.textContent = 'ข้อมูลอัพเดทแล้ว';
  }
}

// Update UI on events
EventManager.on('sync:started', updateSyncUI);
EventManager.on('sync:complete', updateSyncUI);
EventManager.on('sync:online', updateSyncUI);
EventManager.on('sync:offline', updateSyncUI);
</script>

Retry Failed Operations

// Get failed operations
const failed = await SyncManager.getFailedOperations();

if (failed.length > 0) {
  const retry = await DialogManager.confirm(
    `มี ${failed.length} รายการที่ sync ไม่สำเร็จ ต้องการลองใหม่?`
  );

  if (retry) {
    await SyncManager.resetFailedOperations();
    await SyncManager.syncAll();
  }
}

ข้อควรระวัง

⚠️ 1. ตรวจสอบ Network Status

// ❌ ไม่ตรวจสอบ online status
SyncManager.syncAll();

// ✅ ตรวจสอบก่อน
if (navigator.onLine) {
  SyncManager.syncAll();
} else {
  console.log('Offline - will sync later');
}

⚠️ 2. Handle Conflicts

// Server อาจ reject เนื่องจาก data เก่า
SyncManager.init({
  onSyncError: async (error, operation) => {
    if (error.status === 409) { // Conflict
      // Fetch latest and merge
      const latest = await ApiService.get(`/api/${operation.storeName}/${operation.data.id}`);
      // ... resolve conflict
    }
  }
});

⚠️ 3. Unique Operation IDs

// SyncManager สร้าง ID ให้อัตโนมัติ
// แต่ถ้าต้องการ custom ID:
await SyncManager.addPendingOperation({
  id: `order_${orderId}_${Date.now()}`,
  storeName: 'orders',
  method: 'add',
  data: orderData
});

เอกสารที่เกี่ยวข้อง