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.
—
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.
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;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);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:
open: Fired when connection moves to OPEN state
send() after this eventmessage: Fired when data is received
data property with message contentclose: Fired when connection is closed
code, reason, and wasClean propertieserror: Fired on connection errors
heartbeat: Fired when server sends heartbeat
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()
});
});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.
};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);
};Understanding the order in which event handlers are called.
Execution Sequence:
onXXX handler property (if set)addEventListener listeners in order of registrationExample 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 addEventListenerRecommended 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