0
# Event System
1
2
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.
3
4
## Capabilities
5
6
### Event Handler Properties
7
8
Traditional WebSocket-style event handlers for connection lifecycle and data events.
9
10
```javascript { .api }
11
/**
12
* Event handler for connection open event
13
* @type {function|null}
14
* Called when connection is successfully established
15
*/
16
SockJS.prototype.onopen;
17
18
/**
19
* Event handler for incoming messages
20
* @type {function|null}
21
* @param {MessageEvent} event - Event object with data property
22
*/
23
SockJS.prototype.onmessage;
24
25
/**
26
* Event handler for connection close event
27
* @type {function|null}
28
* @param {CloseEvent} event - Event object with code, reason, wasClean properties
29
*/
30
SockJS.prototype.onclose;
31
32
/**
33
* Event handler for connection errors
34
* @type {function|null}
35
* Called when connection encounters an error
36
*/
37
SockJS.prototype.onerror;
38
```
39
40
**Usage Examples:**
41
42
```javascript
43
const sock = new SockJS('https://example.com/sockjs');
44
45
// Set up event handlers
46
sock.onopen = function() {
47
console.log('Connection established');
48
console.log('Using transport:', this.transport);
49
};
50
51
sock.onmessage = function(event) {
52
console.log('Received message:', event.data);
53
console.log('Event type:', event.type); // "message"
54
};
55
56
sock.onclose = function(event) {
57
console.log('Connection closed');
58
console.log('Code:', event.code);
59
console.log('Reason:', event.reason);
60
console.log('Clean close:', event.wasClean);
61
};
62
63
sock.onerror = function() {
64
console.log('Connection error occurred');
65
};
66
67
// Event handlers can be removed by setting to null
68
sock.onmessage = null;
69
```
70
71
### EventTarget Methods
72
73
Modern DOM-compatible event listener methods for more sophisticated event handling.
74
75
```javascript { .api }
76
/**
77
* Add an event listener for the specified event type
78
* @param {string} type - Event type ('open', 'message', 'close', 'error', 'heartbeat')
79
* @param {function} listener - Event handler function
80
* @returns {void}
81
*
82
* Notes:
83
* - Same listener function won't be added twice for the same event type
84
* - Listeners are called after the corresponding onXXX handler
85
*/
86
SockJS.prototype.addEventListener(type, listener);
87
88
/**
89
* Remove an event listener for the specified event type
90
* @param {string} type - Event type to remove listener from
91
* @param {function} listener - Specific listener function to remove
92
* @returns {void}
93
*
94
* Notes:
95
* - Only removes the exact function reference provided
96
* - No-op if listener was not previously added
97
*/
98
SockJS.prototype.removeEventListener(type, listener);
99
100
/**
101
* Dispatch an event to all registered listeners
102
* @param {Event} event - Event object to dispatch
103
* @returns {void}
104
*
105
* Note: Primarily for internal use, but can be used for custom events
106
*/
107
SockJS.prototype.dispatchEvent(event);
108
```
109
110
**Usage Examples:**
111
112
```javascript
113
const sock = new SockJS('https://example.com/sockjs');
114
115
// Define reusable handler functions
116
function handleOpen() {
117
console.log('Connected via addEventListener');
118
}
119
120
function handleMessage(event) {
121
console.log('Message via addEventListener:', event.data);
122
123
// Remove this listener after first message
124
sock.removeEventListener('message', handleMessage);
125
}
126
127
function handleClose(event) {
128
console.log('Closed via addEventListener:', event.code);
129
}
130
131
// Add multiple listeners
132
sock.addEventListener('open', handleOpen);
133
sock.addEventListener('message', handleMessage);
134
sock.addEventListener('close', handleClose);
135
136
// Add multiple listeners for the same event
137
sock.addEventListener('message', function(event) {
138
console.log('Second message handler:', event.data);
139
});
140
141
// Remove specific listener
142
sock.removeEventListener('open', handleOpen);
143
144
// Anonymous functions can't be removed without reference
145
const anonymousHandler = function(event) {
146
console.log('Anonymous handler:', event.data);
147
};
148
sock.addEventListener('message', anonymousHandler);
149
// Later: sock.removeEventListener('message', anonymousHandler);
150
```
151
152
### Event Types
153
154
Available event types and their characteristics.
155
156
```javascript { .api }
157
/**
158
* Event type constants and descriptions
159
*/
160
const EventTypes = {
161
'open': 'Connection successfully established',
162
'message': 'Data received from server',
163
'close': 'Connection closed (normal or error)',
164
'error': 'Connection error occurred',
165
'heartbeat': 'Heartbeat received from server'
166
};
167
```
168
169
**Event Type Details:**
170
171
1. **open**: Fired when connection moves to OPEN state
172
- No additional data in event object
173
- Safe to call `send()` after this event
174
175
2. **message**: Fired when data is received
176
- Event has `data` property with message content
177
- Data is always a string (server must send strings)
178
179
3. **close**: Fired when connection is closed
180
- Event has `code`, `reason`, and `wasClean` properties
181
- Connection cannot be reused after this event
182
183
4. **error**: Fired on connection errors
184
- Typically fired before close event
185
- No additional data in event object
186
187
5. **heartbeat**: Fired when server sends heartbeat
188
- Indicates connection is still alive
189
- No additional data in event object
190
191
**Comprehensive Event Example:**
192
193
```javascript
194
const sock = new SockJS('https://example.com/sockjs');
195
196
// Using both handler properties and addEventListener
197
sock.onopen = function() {
198
console.log('Handler property: opened');
199
};
200
201
sock.addEventListener('open', function() {
202
console.log('Event listener: opened'); // Called after onopen
203
});
204
205
// Multiple message handlers
206
const logMessage = (event) => console.log('Log:', event.data);
207
const processMessage = (event) => {
208
try {
209
const data = JSON.parse(event.data);
210
console.log('Parsed:', data);
211
} catch (e) {
212
console.log('Raw:', event.data);
213
}
214
};
215
216
sock.addEventListener('message', logMessage);
217
sock.addEventListener('message', processMessage);
218
219
// Heartbeat monitoring
220
sock.addEventListener('heartbeat', function() {
221
console.log('Heartbeat received at', new Date());
222
});
223
224
// Error and close handling
225
sock.addEventListener('error', function() {
226
console.log('Connection error detected');
227
});
228
229
sock.addEventListener('close', function(event) {
230
console.log('Connection closed:', {
231
code: event.code,
232
reason: event.reason,
233
wasClean: event.wasClean,
234
timestamp: new Date()
235
});
236
});
237
```
238
239
### Event Objects
240
241
Detailed structure of event objects passed to event handlers.
242
243
```javascript { .api }
244
/**
245
* Base event object structure
246
*/
247
interface SockJSEvent {
248
type: string; // Event type name
249
bubbles: boolean; // Always false
250
cancelable: boolean; // Always false
251
timeStamp: number; // Event creation timestamp
252
}
253
254
/**
255
* Message event object
256
*/
257
interface SockJSMessageEvent extends SockJSEvent {
258
type: 'message';
259
data: any; // Message payload (typically string)
260
}
261
262
/**
263
* Close event object
264
*/
265
interface SockJSCloseEvent extends SockJSEvent {
266
type: 'close';
267
code: number; // Close code (1000, 2xxx, 3xxx-4xxx)
268
reason: string; // Human-readable close reason
269
wasClean: boolean; // Whether close was clean (normal)
270
}
271
272
/**
273
* Simple events (open, error, heartbeat)
274
*/
275
interface SockJSSimpleEvent extends SockJSEvent {
276
type: 'open' | 'error' | 'heartbeat';
277
// No additional properties
278
}
279
```
280
281
**Event Object Usage:**
282
283
```javascript
284
const sock = new SockJS('https://example.com/sockjs');
285
286
sock.onmessage = function(event) {
287
// MessageEvent properties
288
console.log('Type:', event.type); // "message"
289
console.log('Data:', event.data); // Message content
290
console.log('Time:', event.timeStamp); // When event was created
291
console.log('Bubbles:', event.bubbles); // false
292
};
293
294
sock.onclose = function(event) {
295
// CloseEvent properties
296
console.log('Type:', event.type); // "close"
297
console.log('Code:', event.code); // Close code number
298
console.log('Reason:', event.reason); // Close reason string
299
console.log('Clean:', event.wasClean); // Clean close flag
300
console.log('Time:', event.timeStamp); // Event timestamp
301
};
302
303
sock.onopen = function(event) {
304
// Simple event properties
305
console.log('Type:', event.type); // "open"
306
console.log('Time:', event.timeStamp); // Event timestamp
307
// No data, code, reason, etc.
308
};
309
```
310
311
### Custom Event Dispatch
312
313
Advanced usage for custom event handling and testing.
314
315
```javascript { .api }
316
/**
317
* Create and dispatch custom events
318
* Note: Primarily for testing or advanced integration scenarios
319
*/
320
321
// Import event classes (internal, for reference)
322
const Event = require('sockjs-client/lib/event/event');
323
const CloseEvent = require('sockjs-client/lib/event/close');
324
const TransportMessageEvent = require('sockjs-client/lib/event/trans-message');
325
```
326
327
**Custom Event Example:**
328
329
```javascript
330
const sock = new SockJS('https://example.com/sockjs');
331
332
// Listen for custom events
333
sock.addEventListener('custom', function(event) {
334
console.log('Custom event received');
335
});
336
337
// Dispatch custom event (advanced usage)
338
sock.onopen = function() {
339
// Create custom event object
340
const customEvent = {
341
type: 'custom',
342
bubbles: false,
343
cancelable: false,
344
timeStamp: Date.now()
345
};
346
347
// Dispatch it
348
sock.dispatchEvent(customEvent);
349
};
350
```
351
352
## Event Handler Execution Order
353
354
Understanding the order in which event handlers are called.
355
356
**Execution Sequence:**
357
358
1. `onXXX` handler property (if set)
359
2. All `addEventListener` listeners in order of registration
360
3. Event processing completes
361
362
**Example Demonstrating Order:**
363
364
```javascript
365
const sock = new SockJS('https://example.com/sockjs');
366
367
// This will be called first
368
sock.onopen = function() {
369
console.log('1. onopen handler');
370
};
371
372
// These will be called in registration order after onopen
373
sock.addEventListener('open', function() {
374
console.log('2. First addEventListener');
375
});
376
377
sock.addEventListener('open', function() {
378
console.log('3. Second addEventListener');
379
});
380
381
// Output when connection opens:
382
// 1. onopen handler
383
// 2. First addEventListener
384
// 3. Second addEventListener
385
```
386
387
## Event Handling Best Practices
388
389
Recommended patterns for robust event handling.
390
391
**Basic Pattern:**
392
393
```javascript
394
const sock = new SockJS('https://example.com/sockjs');
395
396
sock.onopen = function() {
397
console.log('Connected');
398
// Connection is ready, safe to send
399
sock.send(JSON.stringify({type: 'init'}));
400
};
401
402
sock.onmessage = function(event) {
403
try {
404
const message = JSON.parse(event.data);
405
handleMessage(message);
406
} catch (error) {
407
console.log('Invalid JSON received:', event.data);
408
}
409
};
410
411
sock.onclose = function(event) {
412
console.log('Disconnected:', event.code, event.reason);
413
414
// Reconnection logic
415
if (event.code !== 1000) {
416
setTimeout(() => reconnect(), 5000);
417
}
418
};
419
420
sock.onerror = function() {
421
console.log('Connection error');
422
// Error handling logic
423
};
424
```
425
426
**Advanced Pattern with Cleanup:**
427
428
```javascript
429
function createConnection(url) {
430
const sock = new SockJS(url);
431
const handlers = new Set();
432
433
// Helper to add removable listeners
434
const addListener = (type, handler) => {
435
sock.addEventListener(type, handler);
436
handlers.add(() => sock.removeEventListener(type, handler));
437
};
438
439
// Set up handlers
440
addListener('open', handleOpen);
441
addListener('message', handleMessage);
442
addListener('close', handleClose);
443
addListener('error', handleError);
444
445
// Cleanup function
446
const cleanup = () => {
447
handlers.forEach(remove => remove());
448
handlers.clear();
449
};
450
451
return { sock, cleanup };
452
}
453
454
// Usage
455
const { sock, cleanup } = createConnection('https://example.com/sockjs');
456
457
// Later: cleanup when done
458
cleanup();
459
```