CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-sockjs-client

SockJS-client is a browser JavaScript library that provides a WebSocket-like object for establishing cross-browser, full-duplex communication channels between browsers and web servers.

Pending
Overview
Eval results
Files

events.mddocs/

Event System

SockJS implements a DOM-compatible event system that supports both traditional event handler properties (onopen, onmessage, etc.) and modern event listener methods (addEventListener, removeEventListener). This provides flexibility for different coding styles and integration patterns.

Capabilities

Event Handler Properties

Traditional WebSocket-style event handlers for connection lifecycle and data events.

/**
 * Event handler for connection open event
 * @type {function|null}
 * Called when connection is successfully established
 */
SockJS.prototype.onopen;

/**
 * Event handler for incoming messages
 * @type {function|null}
 * @param {MessageEvent} event - Event object with data property
 */
SockJS.prototype.onmessage;

/**
 * Event handler for connection close event  
 * @type {function|null}
 * @param {CloseEvent} event - Event object with code, reason, wasClean properties
 */
SockJS.prototype.onclose;

/**
 * Event handler for connection errors
 * @type {function|null}
 * Called when connection encounters an error
 */
SockJS.prototype.onerror;

Usage Examples:

const sock = new SockJS('https://example.com/sockjs');

// Set up event handlers
sock.onopen = function() {
  console.log('Connection established');
  console.log('Using transport:', this.transport);
};

sock.onmessage = function(event) {
  console.log('Received message:', event.data);
  console.log('Event type:', event.type); // "message"
};

sock.onclose = function(event) {
  console.log('Connection closed');
  console.log('Code:', event.code);
  console.log('Reason:', event.reason);
  console.log('Clean close:', event.wasClean);
};

sock.onerror = function() {
  console.log('Connection error occurred');
};

// Event handlers can be removed by setting to null
sock.onmessage = null;

EventTarget Methods

Modern DOM-compatible event listener methods for more sophisticated event handling.

/**
 * Add an event listener for the specified event type
 * @param {string} type - Event type ('open', 'message', 'close', 'error', 'heartbeat')
 * @param {function} listener - Event handler function
 * @returns {void}
 * 
 * Notes:
 * - Same listener function won't be added twice for the same event type
 * - Listeners are called after the corresponding onXXX handler
 */
SockJS.prototype.addEventListener(type, listener);

/**
 * Remove an event listener for the specified event type
 * @param {string} type - Event type to remove listener from
 * @param {function} listener - Specific listener function to remove
 * @returns {void}
 * 
 * Notes:
 * - Only removes the exact function reference provided
 * - No-op if listener was not previously added
 */
SockJS.prototype.removeEventListener(type, listener);

/**
 * Dispatch an event to all registered listeners
 * @param {Event} event - Event object to dispatch
 * @returns {void}
 * 
 * Note: Primarily for internal use, but can be used for custom events
 */
SockJS.prototype.dispatchEvent(event);

Usage Examples:

const sock = new SockJS('https://example.com/sockjs');

// Define reusable handler functions
function handleOpen() {
  console.log('Connected via addEventListener');
}

function handleMessage(event) {
  console.log('Message via addEventListener:', event.data);
  
  // Remove this listener after first message
  sock.removeEventListener('message', handleMessage);
}

function handleClose(event) {
  console.log('Closed via addEventListener:', event.code);
}

// Add multiple listeners
sock.addEventListener('open', handleOpen);
sock.addEventListener('message', handleMessage);
sock.addEventListener('close', handleClose);

// Add multiple listeners for the same event
sock.addEventListener('message', function(event) {
  console.log('Second message handler:', event.data);
});

// Remove specific listener
sock.removeEventListener('open', handleOpen);

// Anonymous functions can't be removed without reference
const anonymousHandler = function(event) {
  console.log('Anonymous handler:', event.data);
};
sock.addEventListener('message', anonymousHandler);
// Later: sock.removeEventListener('message', anonymousHandler);

Event Types

Available event types and their characteristics.

/**
 * Event type constants and descriptions
 */
const EventTypes = {
  'open': 'Connection successfully established',
  'message': 'Data received from server', 
  'close': 'Connection closed (normal or error)',
  'error': 'Connection error occurred',
  'heartbeat': 'Heartbeat received from server'
};

Event Type Details:

  1. open: Fired when connection moves to OPEN state

    • No additional data in event object
    • Safe to call send() after this event
  2. message: Fired when data is received

    • Event has data property with message content
    • Data is always a string (server must send strings)
  3. close: Fired when connection is closed

    • Event has code, reason, and wasClean properties
    • Connection cannot be reused after this event
  4. error: Fired on connection errors

    • Typically fired before close event
    • No additional data in event object
  5. heartbeat: Fired when server sends heartbeat

    • Indicates connection is still alive
    • No additional data in event object

Comprehensive Event Example:

const sock = new SockJS('https://example.com/sockjs');

// Using both handler properties and addEventListener
sock.onopen = function() {
  console.log('Handler property: opened');
};

sock.addEventListener('open', function() {
  console.log('Event listener: opened'); // Called after onopen
});

// Multiple message handlers
const logMessage = (event) => console.log('Log:', event.data);
const processMessage = (event) => {
  try {
    const data = JSON.parse(event.data);
    console.log('Parsed:', data);
  } catch (e) {
    console.log('Raw:', event.data);
  }
};

sock.addEventListener('message', logMessage);
sock.addEventListener('message', processMessage);

// Heartbeat monitoring
sock.addEventListener('heartbeat', function() {
  console.log('Heartbeat received at', new Date());
});

// Error and close handling
sock.addEventListener('error', function() {
  console.log('Connection error detected');
});

sock.addEventListener('close', function(event) {
  console.log('Connection closed:', {
    code: event.code,
    reason: event.reason,
    wasClean: event.wasClean,
    timestamp: new Date()
  });
});

Event Objects

Detailed structure of event objects passed to event handlers.

/**
 * Base event object structure
 */
interface SockJSEvent {
  type: string;           // Event type name
  bubbles: boolean;       // Always false
  cancelable: boolean;    // Always false  
  timeStamp: number;      // Event creation timestamp
}

/**
 * Message event object
 */
interface SockJSMessageEvent extends SockJSEvent {
  type: 'message';
  data: any;              // Message payload (typically string)
}

/**
 * Close event object
 */
interface SockJSCloseEvent extends SockJSEvent {
  type: 'close';
  code: number;           // Close code (1000, 2xxx, 3xxx-4xxx)
  reason: string;         // Human-readable close reason
  wasClean: boolean;      // Whether close was clean (normal)
}

/**
 * Simple events (open, error, heartbeat)
 */
interface SockJSSimpleEvent extends SockJSEvent {
  type: 'open' | 'error' | 'heartbeat';
  // No additional properties
}

Event Object Usage:

const sock = new SockJS('https://example.com/sockjs');

sock.onmessage = function(event) {
  // MessageEvent properties
  console.log('Type:', event.type);       // "message"
  console.log('Data:', event.data);       // Message content
  console.log('Time:', event.timeStamp);  // When event was created
  console.log('Bubbles:', event.bubbles); // false
};

sock.onclose = function(event) {
  // CloseEvent properties
  console.log('Type:', event.type);       // "close"
  console.log('Code:', event.code);       // Close code number
  console.log('Reason:', event.reason);   // Close reason string
  console.log('Clean:', event.wasClean);  // Clean close flag
  console.log('Time:', event.timeStamp);  // Event timestamp
};

sock.onopen = function(event) {
  // Simple event properties
  console.log('Type:', event.type);       // "open"
  console.log('Time:', event.timeStamp);  // Event timestamp
  // No data, code, reason, etc.
};

Custom Event Dispatch

Advanced usage for custom event handling and testing.

/**
 * Create and dispatch custom events
 * Note: Primarily for testing or advanced integration scenarios
 */

// Import event classes (internal, for reference)
const Event = require('sockjs-client/lib/event/event');
const CloseEvent = require('sockjs-client/lib/event/close');
const TransportMessageEvent = require('sockjs-client/lib/event/trans-message');

Custom Event Example:

const sock = new SockJS('https://example.com/sockjs');

// Listen for custom events
sock.addEventListener('custom', function(event) {
  console.log('Custom event received');
});

// Dispatch custom event (advanced usage)
sock.onopen = function() {
  // Create custom event object
  const customEvent = {
    type: 'custom',
    bubbles: false,
    cancelable: false,
    timeStamp: Date.now()
  };
  
  // Dispatch it
  sock.dispatchEvent(customEvent);
};

Event Handler Execution Order

Understanding the order in which event handlers are called.

Execution Sequence:

  1. onXXX handler property (if set)
  2. All addEventListener listeners in order of registration
  3. Event processing completes

Example Demonstrating Order:

const sock = new SockJS('https://example.com/sockjs');

// This will be called first
sock.onopen = function() {
  console.log('1. onopen handler');
};

// These will be called in registration order after onopen
sock.addEventListener('open', function() {
  console.log('2. First addEventListener');
});

sock.addEventListener('open', function() {
  console.log('3. Second addEventListener');  
});

// Output when connection opens:
// 1. onopen handler
// 2. First addEventListener  
// 3. Second addEventListener

Event Handling Best Practices

Recommended patterns for robust event handling.

Basic Pattern:

const sock = new SockJS('https://example.com/sockjs');

sock.onopen = function() {
  console.log('Connected');
  // Connection is ready, safe to send
  sock.send(JSON.stringify({type: 'init'}));
};

sock.onmessage = function(event) {
  try {
    const message = JSON.parse(event.data);
    handleMessage(message);
  } catch (error) {
    console.log('Invalid JSON received:', event.data);
  }
};

sock.onclose = function(event) {
  console.log('Disconnected:', event.code, event.reason);
  
  // Reconnection logic
  if (event.code !== 1000) {
    setTimeout(() => reconnect(), 5000);
  }
};

sock.onerror = function() {
  console.log('Connection error');
  // Error handling logic
};

Advanced Pattern with Cleanup:

function createConnection(url) {
  const sock = new SockJS(url);
  const handlers = new Set();
  
  // Helper to add removable listeners
  const addListener = (type, handler) => {
    sock.addEventListener(type, handler);
    handlers.add(() => sock.removeEventListener(type, handler));
  };
  
  // Set up handlers
  addListener('open', handleOpen);
  addListener('message', handleMessage);
  addListener('close', handleClose);
  addListener('error', handleError);
  
  // Cleanup function
  const cleanup = () => {
    handlers.forEach(remove => remove());
    handlers.clear();
  };
  
  return { sock, cleanup };
}

// Usage
const { sock, cleanup } = createConnection('https://example.com/sockjs');

// Later: cleanup when done
cleanup();

Install with Tessl CLI

npx tessl i tessl/npm-sockjs-client

docs

core-api.md

events.md

index.md

transports.md

tile.json